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/io/keycontrol.cpp b/code/io/keycontrol.cpp index 114d45c57af..a54c7d010b8 100644 --- a/code/io/keycontrol.cpp +++ b/code/io/keycontrol.cpp @@ -1614,14 +1614,13 @@ 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()) { - extern void fishtank_start(); - fishtank_start(); + if ((gameseq_get_state() == GS_STATE_MAIN_MENU) && (main_hall_is_retail_vasudan() || main_hall_allows_fish())) { + main_hall_start_fishies(); } } 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/fishtank.cpp b/code/menuui/fishtank.cpp index eecf585f2c3..fab57aea01e 100644 --- a/code/menuui/fishtank.cpp +++ b/code/menuui/fishtank.cpp @@ -7,79 +7,87 @@ * */ - - #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 + 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; -#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" +constexpr size_t MAX_FISH = 24; // was 12.. bigger screens need more fish! +SCP_vector All_fish; -#define FISH_ANIM_WIDTH 100 -#define FISH_ANIM_HEIGHT 30 - -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)){ + // Find a free fish + auto it = std::find_if(All_fish.begin(), All_fish.end(), [](const fish& f) { return !f.swimming; }); + + // No fish left so bail + if (it == All_fish.end()) { return; } - // find a free fish - f = NULL; - for(idx=0; idxleft = frand_range(0.0f, 1.0f) >= 0.5f; + + // Let it freeeeeeee! + f->swimming = true; + + // Set the animation + if (f->left) { + generic_anim_init(&f->anim, Fish_left_anim_name); + + // Doh! Something went wrong. Maybe the fish escaped! + if (generic_anim_stream(&f->anim) == -1) { + f->swimming = false; + generic_anim_init(&f->anim); + } + } else { + generic_anim_init(&f->anim, Fish_right_anim_name); + + // Doh! Something went wrong. Maybe the fish escaped! + if (generic_anim_stream(&f->anim) == -1) { + f->swimming = false; + generic_anim_init(&f->anim); } } - // no fish left - if(f == NULL){ - return; - } - - // left or right - f->left = frand_range(0.0f, 1.0f) < 0.5f ? 0 : 1; + // Pick a scale + f->scale = frand_range(0.5f, 1.0f); - // start location + // 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->anim.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 +95,197 @@ 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; - - // anim instance - anim_play_struct aps; + // 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); - 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->anim.first_frame != -1) { + generic_anim_unload(&f->anim); } - // no longer swimming - f->swimming = 0; + // No longer swimming + f->swimming = false; } -void fishtank_start() +void fishtank_start(const SCP_string& f_left, const 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"; + } - // try and load the fish anim - Fish_left_anim = anim_load(FISH_LEFT_ANIM_NAME); - if(Fish_left_anim == NULL){ + generic_anim fish_left; + generic_anim fish_right; + + // 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; idx 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; } - // process all fish - for(idx=0; idxswimming){ + // Not swimming? + if (!f.swimming) { + ++it; 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; + // 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); + } } - // if he was onscreen before, but is no longer, flush him and make a new fish - if(f->onscreen && !onscreen){ - fish_flush(f); + // Move it along according to its speed settings + f.x += f.x_speed * flFrametime; + f.y += f.y_speed * flFrametime; - fish_generate(); - continue; + // Check if it's on screen still + bool onscreen = false; + 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; } - // otherwise just mark his current status - f->onscreen = onscreen; + // If it was onscreen before but is no longer, yeet it or flush it + if (f.onscreen && !onscreen) { + // 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; + } - // 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 fish if it's onscreen + if (f.onscreen) { + generic_anim_render(&f.anim, flFrametime, (int)f.x, (int)f.y, false, nullptr, f.scale); } + + ++it; } } diff --git a/code/menuui/fishtank.h b/code/menuui/fishtank.h index 8b72256a114..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(); +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 f50a3683796..f9c6f9cb250 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,35 @@ 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("+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); + + 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); @@ -2714,21 +2731,109 @@ void parse_one_main_hall(bool replace, int num_resolutions, int &hall_idx, int & } /** - * Make the vasudan main hall funny + * 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; + } + } + + // 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 (or put them back on if we're toggling off I guess) + if (region_index >= 0) { + // Change the door anim + if (!anim_filename.empty()) { + 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 main hall funny */ 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) */ @@ -2768,3 +2873,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 69317ba4508..398458c8828 100644 --- a/code/menuui/mainhallmenu.h +++ b/code/menuui/mainhallmenu.h @@ -66,6 +66,15 @@ class main_hall_defines int zoom_area_width = -1; int zoom_area_height = -1; + // 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; + interface_snd_id headz_sound_index = InterfaceSounds::VASUDAN_BUP; + // intercom defines ------------------- // # of intercom sounds @@ -205,7 +214,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(); @@ -222,4 +234,6 @@ void main_hall_unpause(); void main_hall_toggle_help(bool enable); +void main_hall_start_fishies(); + #endif