From 346aa91ccb5a3cd3723c9faacdb594a4070295d6 Mon Sep 17 00:00:00 2001 From: mjn-mixael Date: Fri, 6 Sep 2024 15:13:27 -0500 Subject: [PATCH 1/5] Expose fish and headz cheat for custom mainhalls to use --- code/io/keycontrol.cpp | 4 +- code/menuui/mainhallmenu.cpp | 155 ++++++++++++++++++++++++++++------- code/menuui/mainhallmenu.h | 12 ++- 3 files changed, 140 insertions(+), 31 deletions(-) diff --git a/code/io/keycontrol.cpp b/code/io/keycontrol.cpp index 114d45c57af..2d1d08e2fae 100644 --- a/code/io/keycontrol.cpp +++ b/code/io/keycontrol.cpp @@ -1614,14 +1614,14 @@ void game_process_cheats(int k) } if(detectedCheatCode == CHEAT_CODE_FISH){ // only enable in the Vasudan main hall - if ((gameseq_get_state() == GS_STATE_MAIN_MENU) && main_hall_is_vasudan()) { + if ((gameseq_get_state() == GS_STATE_MAIN_MENU) && (main_hall_is_retail_vasudan() || main_hall_allows_fish())) { extern void fishtank_start(); fishtank_start(); } } if(detectedCheatCode == CHEAT_CODE_HEADZ){ // only enable in the Vasudan main hall - if ((gameseq_get_state() == GS_STATE_MAIN_MENU) && main_hall_is_vasudan()) { + if ((gameseq_get_state() == GS_STATE_MAIN_MENU) && (main_hall_is_retail_vasudan() || main_hall_allows_headz())) { main_hall_vasudan_funny(); } } diff --git a/code/menuui/mainhallmenu.cpp b/code/menuui/mainhallmenu.cpp index f50a3683796..3935dac23ce 100644 --- a/code/menuui/mainhallmenu.cpp +++ b/code/menuui/mainhallmenu.cpp @@ -52,6 +52,7 @@ extern void game_process_cheats(int k); // forward declaration void parse_one_main_hall(bool replace, int num_resolutions, int &hall_idx, int &res_idx); +void main_hall_set_door_headz(bool enable, bool init = false); // ---------------------------------------------------------------------------- // MAIN HALL DATA DEFINES @@ -70,8 +71,7 @@ static int Main_hall_music_index = -1; bool Main_hall_poll_key = true; -int Vasudan_funny = 0; -int Vasudan_funny_plate = -1; +bool Vasudan_funny = false; SCP_string Main_hall_cheat = ""; @@ -540,29 +540,6 @@ void main_hall_init(const SCP_string &main_hall_name) // init tooltip shader // nearly black gr_create_shader(&Main_hall_tooltip_shader, 5, 5, 5, 168); - // are we funny? - if (Vasudan_funny && main_hall_is_vasudan()) { - if (!stricmp(Main_hall->bitmap.c_str(), "vhall")) { - Main_hall->door_sounds.at(OPTIONS_REGION).at(0) = InterfaceSounds::VASUDAN_BUP; - Main_hall->door_sounds.at(OPTIONS_REGION).at(1) = InterfaceSounds::VASUDAN_BUP; - - // set head anim. hehe - Main_hall->door_anim_name.at(OPTIONS_REGION) = "vhallheads"; - - // set the background - Main_hall->bitmap = "vhallhead"; - } else if (!stricmp(Main_hall->bitmap.c_str(), "2_vhall")) { - Main_hall->door_sounds.at(OPTIONS_REGION).at(0) = InterfaceSounds::VASUDAN_BUP; - Main_hall->door_sounds.at(OPTIONS_REGION).at(1) = InterfaceSounds::VASUDAN_BUP; - - // set head anim. hehe - Main_hall->door_anim_name.at(OPTIONS_REGION) = "2_vhallheads"; - - // set the background - Main_hall->bitmap = "2_vhallhead"; - } - } - Main_hall_bitmap_w = -1; Main_hall_bitmap_h = -1; @@ -677,6 +654,11 @@ void main_hall_init(const SCP_string &main_hall_name) Main_hall_door_sound_handles.emplace_back(nullptr, sound_handle::invalid()); } + // are we funny? + // Vasudan_funny cannot be true unless the mainhall is retail Vasudan or headz_index >= 0 + // The check is in keycontrol.cpp in the cheats section + main_hall_set_door_headz(Vasudan_funny, true); + // skip the first frame Main_hall_frame_skip = 1; @@ -1485,6 +1467,9 @@ void main_hall_mouse_release_region(int region) } auto sound = Main_hall->door_sounds.at(region).at(1); + if (Vasudan_funny && (main_hall_is_retail_vasudan() || main_hall_allows_headz())) { + sound = Main_hall->headz_sound_index; + } if (sound.isValid()) { @@ -1533,6 +1518,9 @@ void main_hall_mouse_grab_region(int region) auto sound = Main_hall->door_sounds.at(region).at(0); + if (Vasudan_funny && (main_hall_is_retail_vasudan() || main_hall_allows_headz())) { + sound = Main_hall->headz_sound_index; + } if (sound.isValid()) { @@ -2420,6 +2408,25 @@ void parse_one_main_hall(bool replace, int num_resolutions, int &hall_idx, int & m->help_overlay_resolution_index = res_idx; } + if (optional_string("+Allow Fishies:")) { + stuff_boolean(&m->allow_fish); + } + + if (optional_string("+Headz Door Index:")) { + stuff_int(&m->headz_index); + + required_string("+Headz Animation:"); + stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN); + m->headz_anim = temp_string; + + if (optional_string("+Headz Background:")) { + stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN); + m->headz_background = temp_string; + } + + parse_iface_sound("+Headz sound:", &m->headz_sound_index); + } + // zoom area if (optional_string("+Zoom To:")) { stuff_int(&m->zoom_area_width); @@ -2713,22 +2720,114 @@ void parse_one_main_hall(bool replace, int num_resolutions, int &hall_idx, int & } } +/** + * Change the selected door and background to the provided headz animation + */ +void main_hall_set_door_headz(bool enable, bool init) +{ + // Skip this if we're initing the mainhall and we're not enabling headz + if (init && !enable) { + return; + } + + int region_index = -1; + SCP_string anim_filename; + SCP_string bg_filename; + + if (!stricmp(Main_hall->bitmap.c_str(), "vhall")) { + region_index = OPTIONS_REGION; + if (enable) { + anim_filename = "vhallheads"; + bg_filename = "vhallhead"; + } + } else if (!stricmp(Main_hall->bitmap.c_str(), "2_vhall")) { + region_index = OPTIONS_REGION; + if (enable) { + anim_filename = "2_vhallheads"; + bg_filename = "2_vhallhead"; + } + } else if ((Main_hall->headz_index >= 0) && (Main_hall->headz_index < Main_hall->num_door_animations) && !Main_hall->headz_anim.empty()) { + region_index = Main_hall->headz_index; + if (enable) { + anim_filename = Main_hall->headz_anim; + bg_filename = Main_hall->headz_background; + } + // Custom mainhalls don't need to change the background because we have true transparency now + } + + // If we're toggling headz off + if (!enable) { + anim_filename = Main_hall->door_anim_name.at(region_index); + bg_filename = Main_hall->bitmap; + } + + // If we got a match, then let's rip off some headz + if (region_index >= 0) { + // Change the door anim + if (!anim_filename.empty()) { + // On init we skip setting frames + int cur_frame; + float anim_time; + + cur_frame = Main_hall_door_anim.at(region_index).current_frame; + anim_time = Main_hall_door_anim.at(region_index).anim_time; + + generic_anim_unload(&Main_hall_door_anim.at(region_index)); + generic_anim_init(&Main_hall_door_anim.at(region_index), anim_filename); + + if (generic_anim_stream(&Main_hall_door_anim.at(region_index)) == -1) { + nprintf(("General", "WARNING: Could not load door anim %s in main hall\n", anim_filename.c_str())); + } else { + Main_hall_door_anim.at(region_index).direction = GENERIC_ANIM_DIRECTION_BACKWARDS | GENERIC_ANIM_DIRECTION_NOLOOP; + } + + Main_hall_door_anim.at(region_index).current_frame = cur_frame; + Main_hall_door_anim.at(region_index).anim_time = anim_time; + } + + // Change the background + if (!bg_filename.empty()) { + bm_release(Main_hall_bitmap); + Main_hall_bitmap = bm_load(bg_filename); + } + } +} + /** * Make the vasudan main hall funny + * In retail you had to leave the mainhall and return for it to actually take effect + * Custom mainhalls can take effect immediately, though */ void main_hall_vasudan_funny() { - Vasudan_funny = 1; + Vasudan_funny = !Vasudan_funny; + main_hall_set_door_headz(Vasudan_funny); } /** - * Lookup if Vasudan main hall, based upon background graphics + * Lookup if retail Vasudan main hall, based upon background graphics */ -bool main_hall_is_vasudan() +bool main_hall_is_retail_vasudan() { return !stricmp(Main_hall->bitmap.c_str(), "vhall") || !stricmp(Main_hall->bitmap.c_str(), "2_vhall"); } +/** +* Lookup if fish are allowed in a custom main hall +*/ +bool main_hall_allows_fish() +{ + return Main_hall->allow_fish; +} + +/** +* Lookup if a headz graphic is defined in a custom main hall +*/ +bool main_hall_allows_headz() +{ + return Main_hall->headz_index >= 0 && !Main_hall->headz_anim.empty(); +} + /** * Silence sounds on mainhall if we hit a pause mode (ie. lost window focus, minimized, etc) */ diff --git a/code/menuui/mainhallmenu.h b/code/menuui/mainhallmenu.h index 69317ba4508..8da0ad3c822 100644 --- a/code/menuui/mainhallmenu.h +++ b/code/menuui/mainhallmenu.h @@ -66,6 +66,13 @@ class main_hall_defines int zoom_area_width = -1; int zoom_area_height = -1; + // allow fishies! (and headz...) + bool allow_fish = false; + int headz_index = -1; + SCP_string headz_anim; + SCP_string headz_background; + interface_snd_id headz_sound_index = InterfaceSounds::VASUDAN_BUP; + // intercom defines ------------------- // # of intercom sounds @@ -205,7 +212,10 @@ int main_hall_get_overlay_resolution_index(); int main_hall_id(); // Vasudan? -bool main_hall_is_vasudan(); +bool main_hall_is_retail_vasudan(); + +bool main_hall_allows_fish(); +bool main_hall_allows_headz(); // start the ambient sounds playing in the main hall void main_hall_start_ambient(); From 9f991b04afd79faf749a75dae05233a2e4e2036e Mon Sep 17 00:00:00 2001 From: mjn-mixael Date: Fri, 6 Sep 2024 17:12:11 -0500 Subject: [PATCH 2/5] Upgrade fishtank to allow for all anim types and allow mainhalls to manually set the fish anim file --- code/io/keycontrol.cpp | 3 +- code/menuui/fishtank.cpp | 264 ++++++++++++++++------------------- code/menuui/fishtank.h | 2 +- code/menuui/mainhallmenu.cpp | 18 +++ code/menuui/mainhallmenu.h | 4 + 5 files changed, 148 insertions(+), 143 deletions(-) diff --git a/code/io/keycontrol.cpp b/code/io/keycontrol.cpp index 2d1d08e2fae..a54c7d010b8 100644 --- a/code/io/keycontrol.cpp +++ b/code/io/keycontrol.cpp @@ -1615,8 +1615,7 @@ void game_process_cheats(int k) if(detectedCheatCode == CHEAT_CODE_FISH){ // only enable in the Vasudan main hall if ((gameseq_get_state() == GS_STATE_MAIN_MENU) && (main_hall_is_retail_vasudan() || main_hall_allows_fish())) { - extern void fishtank_start(); - fishtank_start(); + main_hall_start_fishies(); } } if(detectedCheatCode == CHEAT_CODE_HEADZ){ diff --git a/code/menuui/fishtank.cpp b/code/menuui/fishtank.cpp index eecf585f2c3..1c9afc0a233 100644 --- a/code/menuui/fishtank.cpp +++ b/code/menuui/fishtank.cpp @@ -7,79 +7,83 @@ * */ - - #include "anim/animplay.h" #include "anim/packunpack.h" +#include "graphics/generic.h" #include "freespace.h" #include "gamesequence/gamesequence.h" #include "menuui/fishtank.h" - - // fish typedef struct fish { float x, y; // x and y coords float x_speed, y_speed; // x and y speed int left; // left or right - anim_instance *a; // tha animation - int onscreen; - int swimming; // whee + generic_anim ga; // the animation + bool onscreen; + bool swimming; // whee } fish; -#define MAX_FISH 12 -fish Fish[MAX_FISH]; - -// fish anim name -#define FISH_LEFT_ANIM_NAME "f_left.ani" -#define FISH_RIGHT_ANIM_NAME "f_right.ani" -#define FISH_ANIM_WIDTH 100 -#define FISH_ANIM_HEIGHT 30 +#define MAX_FISH 24 // was 12.. bigger screens need more fish! +SCP_vector All_fish; -anim *Fish_left_anim = NULL; -anim *Fish_right_anim = NULL; +// fish anim names +SCP_string Fish_left_anim_name; +SCP_string Fish_right_anim_name; int Fish_inited = 0; void fish_generate() { - fish *f; - int idx; - - if(!Fish_inited){ + if (!Fish_inited) { return; } - // bogus anims - if((Fish_left_anim == NULL) || (Fish_right_anim == NULL)){ - return; - } + // Find a free fish + auto it = std::find_if(All_fish.begin(), All_fish.end(), [](const fish& f) { return !f.swimming; }); - // find a free fish - f = NULL; - for(idx=0; idxleft = frand_range(0.0f, 1.0f) < 0.5f ? 0 : 1; - // start location + // Let it freeeeeeee! + f->swimming = true; + + // Set the animation + if (f->left) { + generic_anim_init(&f->ga, Fish_left_anim_name); + + // Doh! Something went wrong. Maybe the fish escaped! + if (generic_anim_stream(&f->ga) == -1) { + f->swimming = false; + generic_anim_init(&f->ga); + } + } else { + generic_anim_init(&f->ga, Fish_right_anim_name); + + // Doh! Something went wrong. Maybe the fish escaped! + if (generic_anim_stream(&f->ga) == -1) { + f->swimming = false; + generic_anim_init(&f->ga); + } + } + + // Pick a starting location if(f->left){ f->x = gr_screen.max_w_unscaled_zoomed + frand_range(0.0f, 50.0f); } else { - f->x = frand_range(0.0f, -50.0f) - FISH_ANIM_WIDTH; + f->x = frand_range(0.0f, -50.0f) - f->ga.width; } f->y = frand_range(-40.0f, (float)gr_screen.max_h_unscaled_zoomed + 40.0f); - // speed + // Maybe give it zoomies. Maybe give it a sedative. if(f->left){ f->x_speed = frand_range(-1.0f, -15.0f); } else { @@ -87,167 +91,147 @@ void fish_generate() } f->y_speed = frand_range(0.0f, 1.0f) < 0.5f ? frand_range(1.0f, 4.0f) : frand_range(-1.0f, -4.0f); - // all fish start out offscreen - f->onscreen = 0; - - // he's swimming - f->swimming = 1; + // Fish can be way too slow on big screens cause this was written for 1024 pixels wide MAX. So let's scale it for our current screen size. + f->y_speed *= (gr_screen.max_h / 786.0f); + f->x_speed *= (gr_screen.max_w / 1024.0f); - // anim instance - anim_play_struct aps; - - if(f->left){ - anim_play_init(&aps, Fish_left_anim, (int)f->x, (int)f->y); - f->a = anim_play(&aps); - - // doh. cancel him - if(f->a == NULL){ - f->swimming = 0; - } else { - f->a->screen_id = GS_STATE_MAIN_MENU; - f->a->looped = 1; - f->a->framerate_independent = 1; - } - } else { - anim_play_init(&aps, Fish_right_anim, (int)f->x, (int)f->y); - f->a = anim_play(&aps); - - // doh. cancel him - if(f->a == NULL){ - f->swimming = 0; - } else { - f->a->screen_id = GS_STATE_MAIN_MENU; - f->a->looped = 1; - f->a->framerate_independent = 1; - } - } + // All fish start out offscreen + f->onscreen = false; } void fish_flush(fish *f) { - // bogus - if(f == NULL){ + // Bad fish! + if(f == nullptr){ return; } - // release his render instance - if(f->a != NULL){ - anim_release_render_instance(f->a); - f->a = NULL; + // Catch and release or something + if (f->ga.first_frame != -1) { + generic_anim_unload(&f->ga); } - // no longer swimming - f->swimming = 0; + // No longer swimming + f->swimming = false; } -void fishtank_start() +void fishtank_start(SCP_string f_left, SCP_string f_right) { - int idx; - if(Fish_inited){ return; } + + // Get our anim names or use retail name + if (!f_left.empty()) { + Fish_left_anim_name = f_left; + } else { + Fish_left_anim_name = "f_left"; + } + + if (!f_left.empty()) { + Fish_right_anim_name = f_right; + } else { + Fish_right_anim_name = "f_right"; + } + + generic_anim fish_left; + generic_anim fish_right; - // try and load the fish anim - Fish_left_anim = anim_load(FISH_LEFT_ANIM_NAME); - if(Fish_left_anim == NULL){ + // Test that we can load the anims. Bail if we can't. Unload and continue if we can. + generic_anim_init(&fish_left, Fish_left_anim_name); + if (generic_anim_stream(&fish_left) == -1) { + Warning(LOCATION, "Could not load fish tank animation %s", Fish_left_anim_name.c_str()); return; } - Fish_right_anim = anim_load(FISH_RIGHT_ANIM_NAME); - if(Fish_right_anim == NULL){ + generic_anim_unload(&fish_left); + + generic_anim_init(&fish_right, Fish_right_anim_name); + if (generic_anim_stream(&fish_right) == -1) { + Warning(LOCATION, "Could not load fish tank animation %s", Fish_right_anim_name.c_str()); return; } + generic_anim_unload(&fish_right); - // no anim instances - for(idx=0; idxswimming){ + // Process all fish + for (fish& f : All_fish) { + // Not swimming? + if (!f.swimming) { continue; } - // move him along - f->x += f->x_speed * flFrametime; - f->y += f->y_speed * flFrametime; + // Small chance to swap vertical direction + if (frand_range(0.0f, 1.0f) < 0.001f) { + f.y_speed *= -1; + } - // is he currently onscreen ? - onscreen = 0; - if( (f->x < (float)gr_screen.max_w_unscaled_zoomed) && ((f->x + FISH_ANIM_WIDTH) >= 0.0f) && - (f->y < (float)gr_screen.max_h_unscaled_zoomed) && ((f->y + FISH_ANIM_HEIGHT) >= 0.0f) ){ - onscreen = 1; + // Move it along according to it's speed settings + f.x += f.x_speed * flFrametime; + f.y += f.y_speed * flFrametime; + + // Check if it's on screen still + bool onscreen = false; + if ((f.x < (float)gr_screen.max_w_unscaled_zoomed) && ((f.x + f.ga.width) >= 0.0f) && + (f.y < (float)gr_screen.max_h_unscaled_zoomed) && ((f.y + f.ga.height) >= 0.0f)) { + onscreen = true; } - // if he was onscreen before, but is no longer, flush him and make a new fish - if(f->onscreen && !onscreen){ - fish_flush(f); + // If it was onscreen before, but is no longer, flush it (down the toilet?!) and make a new fish + if (f.onscreen && !onscreen) { + fish_flush(&f); fish_generate(); continue; } - // otherwise just mark his current status - f->onscreen = onscreen; - - // render - if(f->onscreen){ - // set coords - f->a->x = (int)f->x; - f->a->y = (int)f->y; + // Otherwise just mark its current status + f.onscreen = onscreen; - anim_render_one(GS_STATE_MAIN_MENU, f->a, flFrametime); + // Render the fishy! + if (f.onscreen) { + generic_anim_render(&f.ga, flFrametime, (int)f.x, (int)f.y); } } } diff --git a/code/menuui/fishtank.h b/code/menuui/fishtank.h index 8b72256a114..b003631ca24 100644 --- a/code/menuui/fishtank.h +++ b/code/menuui/fishtank.h @@ -12,7 +12,7 @@ #ifndef __FISHTANK_H__ #define __FISHTANK_H__ -void fishtank_start(); +void fishtank_start(SCP_string f_left, SCP_string f_right); void fishtank_stop(); void fishtank_process(); diff --git a/code/menuui/mainhallmenu.cpp b/code/menuui/mainhallmenu.cpp index 3935dac23ce..78eee6f2d14 100644 --- a/code/menuui/mainhallmenu.cpp +++ b/code/menuui/mainhallmenu.cpp @@ -2412,6 +2412,16 @@ void parse_one_main_hall(bool replace, int num_resolutions, int &hall_idx, int & stuff_boolean(&m->allow_fish); } + if (optional_string("+Left Fish Anim:")) { + stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN); + m->l_fish_anim = temp_string; + } + + if (optional_string("+Right Fish Anim:")) { + stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN); + m->r_fish_anim = temp_string; + } + if (optional_string("+Headz Door Index:")) { stuff_int(&m->headz_index); @@ -2867,3 +2877,11 @@ void main_hall_toggle_help(bool enable) { help_overlay_set_state(Main_hall_overlay_id, main_hall_get_overlay_resolution_index(), (int)enable); } + +/** +* Start the fishies! +*/ +void main_hall_start_fishies() +{ + fishtank_start(Main_hall->l_fish_anim, Main_hall->r_fish_anim); +} \ No newline at end of file diff --git a/code/menuui/mainhallmenu.h b/code/menuui/mainhallmenu.h index 8da0ad3c822..398458c8828 100644 --- a/code/menuui/mainhallmenu.h +++ b/code/menuui/mainhallmenu.h @@ -68,6 +68,8 @@ class main_hall_defines // allow fishies! (and headz...) bool allow_fish = false; + SCP_string l_fish_anim; + SCP_string r_fish_anim; int headz_index = -1; SCP_string headz_anim; SCP_string headz_background; @@ -232,4 +234,6 @@ void main_hall_unpause(); void main_hall_toggle_help(bool enable); +void main_hall_start_fishies(); + #endif From c11d09a6a7352fe5251155551fcd0eaeccb421c0 Mon Sep 17 00:00:00 2001 From: mjn-mixael Date: Fri, 6 Sep 2024 21:25:50 -0500 Subject: [PATCH 3/5] Clang clang clang! Clanging on muh brain! --- code/menuui/fishtank.cpp | 4 ++-- code/menuui/fishtank.h | 2 +- code/menuui/mainhallmenu.cpp | 8 ++------ 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/code/menuui/fishtank.cpp b/code/menuui/fishtank.cpp index 1c9afc0a233..ad9c7ad5dbc 100644 --- a/code/menuui/fishtank.cpp +++ b/code/menuui/fishtank.cpp @@ -24,7 +24,7 @@ typedef struct fish { bool swimming; // whee } fish; -#define MAX_FISH 24 // was 12.. bigger screens need more fish! +constexpr int MAX_FISH = 24; // was 12.. bigger screens need more fish! SCP_vector All_fish; // fish anim names @@ -115,7 +115,7 @@ void fish_flush(fish *f) f->swimming = false; } -void fishtank_start(SCP_string f_left, SCP_string f_right) +void fishtank_start(const SCP_string& f_left, const SCP_string& f_right) { if(Fish_inited){ return; diff --git a/code/menuui/fishtank.h b/code/menuui/fishtank.h index b003631ca24..f038cfb23dd 100644 --- a/code/menuui/fishtank.h +++ b/code/menuui/fishtank.h @@ -12,7 +12,7 @@ #ifndef __FISHTANK_H__ #define __FISHTANK_H__ -void fishtank_start(SCP_string f_left, SCP_string f_right); +void fishtank_start(const SCP_string& f_left, const SCP_string& f_right); void fishtank_stop(); void fishtank_process(); diff --git a/code/menuui/mainhallmenu.cpp b/code/menuui/mainhallmenu.cpp index 78eee6f2d14..f9c6f9cb250 100644 --- a/code/menuui/mainhallmenu.cpp +++ b/code/menuui/mainhallmenu.cpp @@ -2762,7 +2762,6 @@ void main_hall_set_door_headz(bool enable, bool init) anim_filename = Main_hall->headz_anim; bg_filename = Main_hall->headz_background; } - // Custom mainhalls don't need to change the background because we have true transparency now } // If we're toggling headz off @@ -2771,11 +2770,10 @@ void main_hall_set_door_headz(bool enable, bool init) bg_filename = Main_hall->bitmap; } - // If we got a match, then let's rip off some headz + // If we got a match, then let's rip off some headz (or put them back on if we're toggling off I guess) if (region_index >= 0) { // Change the door anim if (!anim_filename.empty()) { - // On init we skip setting frames int cur_frame; float anim_time; @@ -2804,9 +2802,7 @@ void main_hall_set_door_headz(bool enable, bool init) } /** - * Make the vasudan main hall funny - * In retail you had to leave the mainhall and return for it to actually take effect - * Custom mainhalls can take effect immediately, though + * Make the main hall funny */ void main_hall_vasudan_funny() { From 7511988d99a679446b92ed35f1d7e3b61ccee48b Mon Sep 17 00:00:00 2001 From: mjn-mixael Date: Fri, 6 Sep 2024 22:01:01 -0500 Subject: [PATCH 4/5] a little additional cleanliness and clarity --- code/menuui/fishtank.cpp | 42 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/code/menuui/fishtank.cpp b/code/menuui/fishtank.cpp index ad9c7ad5dbc..1d209db358b 100644 --- a/code/menuui/fishtank.cpp +++ b/code/menuui/fishtank.cpp @@ -16,12 +16,12 @@ // fish typedef struct fish { - float x, y; // x and y coords - float x_speed, y_speed; // x and y speed - int left; // left or right - generic_anim ga; // the animation - bool onscreen; - bool swimming; // whee + float x, y; // x and y coords + float x_speed, y_speed; // x and y speed + bool left; // left or right + generic_anim anim; // the animation + bool onscreen; // visible? + bool swimming; // whee } fish; constexpr int MAX_FISH = 24; // was 12.. bigger screens need more fish! @@ -51,27 +51,27 @@ void fish_generate() fish* f = &(*it); // Pick a direction randomly - f->left = frand_range(0.0f, 1.0f) < 0.5f ? 0 : 1; + f->left = frand_range(0.0f, 1.0f) < 0.5f ? false : true; // Let it freeeeeeee! f->swimming = true; // Set the animation if (f->left) { - generic_anim_init(&f->ga, Fish_left_anim_name); + generic_anim_init(&f->anim, Fish_left_anim_name); // Doh! Something went wrong. Maybe the fish escaped! - if (generic_anim_stream(&f->ga) == -1) { + if (generic_anim_stream(&f->anim) == -1) { f->swimming = false; - generic_anim_init(&f->ga); + generic_anim_init(&f->anim); } } else { - generic_anim_init(&f->ga, Fish_right_anim_name); + generic_anim_init(&f->anim, Fish_right_anim_name); // Doh! Something went wrong. Maybe the fish escaped! - if (generic_anim_stream(&f->ga) == -1) { + if (generic_anim_stream(&f->anim) == -1) { f->swimming = false; - generic_anim_init(&f->ga); + generic_anim_init(&f->anim); } } @@ -79,7 +79,7 @@ void fish_generate() if(f->left){ f->x = gr_screen.max_w_unscaled_zoomed + frand_range(0.0f, 50.0f); } else { - f->x = frand_range(0.0f, -50.0f) - f->ga.width; + f->x = frand_range(0.0f, -50.0f) - f->anim.width; } f->y = frand_range(-40.0f, (float)gr_screen.max_h_unscaled_zoomed + 40.0f); @@ -107,8 +107,8 @@ void fish_flush(fish *f) } // Catch and release or something - if (f->ga.first_frame != -1) { - generic_anim_unload(&f->ga); + if (f->anim.first_frame != -1) { + generic_anim_unload(&f->anim); } // No longer swimming @@ -176,8 +176,8 @@ void fishtank_stop() // Release stuff for (fish& f : All_fish) { - if (f.ga.first_frame != -1) { - generic_anim_unload(&f.ga); + if (f.anim.first_frame != -1) { + generic_anim_unload(&f.anim); } f.swimming = false; } @@ -213,8 +213,8 @@ void fishtank_process() // Check if it's on screen still bool onscreen = false; - if ((f.x < (float)gr_screen.max_w_unscaled_zoomed) && ((f.x + f.ga.width) >= 0.0f) && - (f.y < (float)gr_screen.max_h_unscaled_zoomed) && ((f.y + f.ga.height) >= 0.0f)) { + if ((f.x < (float)gr_screen.max_w_unscaled_zoomed) && ((f.x + f.anim.width) >= 0.0f) && + (f.y < (float)gr_screen.max_h_unscaled_zoomed) && ((f.y + f.anim.height) >= 0.0f)) { onscreen = true; } @@ -231,7 +231,7 @@ void fishtank_process() // Render the fishy! if (f.onscreen) { - generic_anim_render(&f.ga, flFrametime, (int)f.x, (int)f.y); + generic_anim_render(&f.anim, flFrametime, (int)f.x, (int)f.y); } } } From 961f1293d7d54fa6c4491e50b667b358f6a48fcd Mon Sep 17 00:00:00 2001 From: mjn-mixael Date: Sat, 7 Sep 2024 00:15:03 -0500 Subject: [PATCH 5/5] why am I spending so much effort on this lol --- code/graphics/2d.cpp | 7 +++- code/graphics/2d.h | 2 +- code/graphics/generic.cpp | 6 ++-- code/graphics/generic.h | 2 +- code/menuui/fishtank.cpp | 76 +++++++++++++++++++++++++++++++++------ 5 files changed, 76 insertions(+), 17 deletions(-) diff --git a/code/graphics/2d.cpp b/code/graphics/2d.cpp index 8acce7cf451..d0c147e4fc6 100644 --- a/code/graphics/2d.cpp +++ b/code/graphics/2d.cpp @@ -1896,7 +1896,7 @@ void gr_set_shader(shader *shade) } // new bitmap functions -void gr_bitmap(int _x, int _y, int resize_mode) +void gr_bitmap(int _x, int _y, int resize_mode, float scale_factor) { GR_DEBUG_SCOPE("2D Bitmap"); @@ -1910,6 +1910,11 @@ void gr_bitmap(int _x, int _y, int resize_mode) bm_get_info(gr_screen.current_bitmap, &_w, &_h, NULL, NULL, NULL); + if (scale_factor != 1.0f) { + _w = static_cast(_w * scale_factor); + _h = static_cast(_h * scale_factor); + } + x = i2fl(_x); y = i2fl(_y); w = i2fl(_w); diff --git a/code/graphics/2d.h b/code/graphics/2d.h index 54b6d690146..1d520ffac27 100644 --- a/code/graphics/2d.h +++ b/code/graphics/2d.h @@ -1317,7 +1317,7 @@ void gr_create_shader(shader *shade, ubyte r, ubyte g, ubyte b, ubyte c); void gr_set_shader(shader *shade); // new bitmap functions -void gr_bitmap(int x, int y, int resize_mode = GR_RESIZE_FULL); +void gr_bitmap(int x, int y, int resize_mode = GR_RESIZE_FULL, float scale_factor = 1.0f); void gr_bitmap_uv(int _x, int _y, int _w, int _h, float _u0, float _v0, float _u1, float _v1, int resize_mode = GR_RESIZE_FULL); // special function for drawing polylines. this function is specifically intended for diff --git a/code/graphics/generic.cpp b/code/graphics/generic.cpp index 19f3a3153fb..3622a404a03 100644 --- a/code/graphics/generic.cpp +++ b/code/graphics/generic.cpp @@ -697,7 +697,7 @@ void generic_anim_render_variable_frame_delay(generic_anim* ga, float frametime, * @param [in] y 2D screen y co-ordinate to render at * @param [in] menu select if this is rendered in menu screen, or fullscreen */ -void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu, const generic_extras *ge) +void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu, const generic_extras *ge, float scale_factor) { if ((ge != nullptr) && (ga->use_hud_color == true)) { Warning(LOCATION, "Monochrome generic anims can't use extra info (yet)"); @@ -719,11 +719,11 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m ga->previous_frame = ga->current_frame; if(ga->use_hud_color) { - gr_aabitmap(x, y, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL)); + gr_aabitmap(x, y, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL), false, scale_factor); } else { if (ge == nullptr) { - gr_bitmap(x, y, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL)); + gr_bitmap(x, y, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL), scale_factor); } else if (ge->draw == true) { // currently only for lua streaminganim objects diff --git a/code/graphics/generic.h b/code/graphics/generic.h index 8b1fd457b98..dd3ca01c1b2 100644 --- a/code/graphics/generic.h +++ b/code/graphics/generic.h @@ -90,7 +90,7 @@ int generic_anim_load(generic_anim *ga); int generic_anim_stream(generic_anim *ga, const bool cache = true); int generic_bitmap_load(generic_bitmap *gb); void generic_anim_unload(generic_anim *ga); -void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu = false, const generic_extras *ge = nullptr); +void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu = false, const generic_extras *ge = nullptr, float scale_factor = 1.0f); void generic_anim_bitmap_set(generic_anim* ga, float frametime, const generic_extras* ge = nullptr); void generic_anim_reset(generic_anim *ga); #endif diff --git a/code/menuui/fishtank.cpp b/code/menuui/fishtank.cpp index 1d209db358b..fab57aea01e 100644 --- a/code/menuui/fishtank.cpp +++ b/code/menuui/fishtank.cpp @@ -18,13 +18,14 @@ typedef struct fish { float x, y; // x and y coords float x_speed, y_speed; // x and y speed + float scale; // big fish or small fish? bool left; // left or right generic_anim anim; // the animation bool onscreen; // visible? bool swimming; // whee } fish; -constexpr int MAX_FISH = 24; // was 12.. bigger screens need more fish! +constexpr size_t MAX_FISH = 24; // was 12.. bigger screens need more fish! SCP_vector All_fish; // fish anim names @@ -51,7 +52,7 @@ void fish_generate() fish* f = &(*it); // Pick a direction randomly - f->left = frand_range(0.0f, 1.0f) < 0.5f ? false : true; + f->left = frand_range(0.0f, 1.0f) >= 0.5f; // Let it freeeeeeee! f->swimming = true; @@ -75,6 +76,9 @@ void fish_generate() } } + // Pick a scale + f->scale = frand_range(0.5f, 1.0f); + // Pick a starting location if(f->left){ f->x = gr_screen.max_w_unscaled_zoomed + frand_range(0.0f, 50.0f); @@ -189,16 +193,50 @@ void fishtank_stop() Fish_inited = 0; } +void fishtank_change_speed(float& speed, float increase, float decrease, float multiplier) +{ + float speed_modifier = (frand_range(0.0f, 1.0f) < 0.5f) ? increase : decrease; + float min = 5.0f * multiplier; + float max = 20.0f * multiplier; + + // Positive speed + if (speed > 0.0f) { + if ((speed < min && speed_modifier == decrease) || (speed > max && speed_modifier == increase)) { + speed_modifier = 1.0f; + } + // Negative speed + } else { + if ((speed > -min && speed_modifier == decrease) || (speed < -max && speed_modifier == increase)) { + speed_modifier = 1.0f; + } + } + + speed = speed * speed_modifier; +} + void fishtank_process() { if(!Fish_inited){ return; } + // Small chance to add a fish + if (All_fish.size() < MAX_FISH) { + if (frand_range(0.0f, 1.0f) < 0.0005f) { + fish new_fish; + new_fish.swimming = false; + All_fish.push_back(new_fish); + fish_generate(); + } + } + // Process all fish - for (fish& f : All_fish) { + for (auto it = All_fish.begin(); it != All_fish.end();) { + fish& f = *it; + // Not swimming? if (!f.swimming) { + ++it; continue; } @@ -207,7 +245,16 @@ void fishtank_process() f.y_speed *= -1; } - // Move it along according to it's speed settings + // Small chance to slightly change speed + if (frand_range(0.0f, 1.0f) < 0.001f) { + if (frand_range(0.0f, 1.0f) < 0.5f) { + fishtank_change_speed(f.x_speed, 1.7f, 0.5f, gr_screen.max_w / 1024.0f); + } else { + fishtank_change_speed(f.y_speed, 1.1f, 0.9f, gr_screen.max_h / 786.0f); + } + } + + // Move it along according to its speed settings f.x += f.x_speed * flFrametime; f.y += f.y_speed * flFrametime; @@ -218,20 +265,27 @@ void fishtank_process() onscreen = true; } - // If it was onscreen before, but is no longer, flush it (down the toilet?!) and make a new fish + // If it was onscreen before but is no longer, yeet it or flush it if (f.onscreen && !onscreen) { - fish_flush(&f); - - fish_generate(); + // Small chance to yeet the fish instead of flushing it. I didn't come up with this language. Don't ask me. + if (frand_range(0.0f, 1.0f) < 0.3f) { + it = All_fish.erase(it); + } else { + fish_flush(&f); // Flush the fish and keep it in the pool. How does that make sense? + fish_generate(); + ++it; + } continue; } - // Otherwise just mark its current status + // Otherwise, just mark its current status f.onscreen = onscreen; - // Render the fishy! + // Render the fish if it's onscreen if (f.onscreen) { - generic_anim_render(&f.anim, flFrametime, (int)f.x, (int)f.y); + generic_anim_render(&f.anim, flFrametime, (int)f.x, (int)f.y, false, nullptr, f.scale); } + + ++it; } }