diff --git a/README.md b/README.md index 98dd3b6d..768e4924 100644 --- a/README.md +++ b/README.md @@ -565,11 +565,15 @@ * Shovels automatically picked up * Records automatically picked up * Gramophone initially spawns at Excavation Site gramophone table -* Teleporters stay active after picking up gramophone -* Teleporters in The Crazy Place become active when placing gramophone -* Players face away from the teleporters when returning from The Crazy Place -* Players can teleport while prone * Musical parts no longer show on HUD +* Generators: increased capture reward points from 100 to 200 +* Generators: always give back refund points if player was in the generator zone when captured +* Generators: recapture round zombies only drop Max Ammo if killed before taking first generator +* Generators: fixed an issue where recapture sound and fx would play twice +* Teleporters: stay active after picking up gramophone +* Teleporters: placing gramophone activates The Crazy Place teleporters +* Teleporters: players face away from the teleporters when returning from The Crazy Place +* Teleporters: players can teleport while prone * Der Wunderfizz: increased cost from 1500 to 2500 * Der Wunderfizz: all perks have an equal chance of being obtained * Rituals of the Ancients: spend points challenge reward changed from Double Tap perk to a random perk that the player does not have (perk does not change if reward is reopened) diff --git a/scripts/zm/replaced/zm_tomb_capture_zones.gsc b/scripts/zm/replaced/zm_tomb_capture_zones.gsc new file mode 100644 index 00000000..4e477de0 --- /dev/null +++ b/scripts/zm/replaced/zm_tomb_capture_zones.gsc @@ -0,0 +1,382 @@ +#include common_scripts\utility; +#include maps\mp\_utility; +#include maps\mp\zombies\_zm_utility; +#include maps\mp\zombies\_zm_score; +#include maps\mp\zombies\_zm_laststand; +#include maps\mp\zombies\_zm_zonemgr; +#include maps\mp\animscripts\zm_death; +#include maps\mp\zm_tomb_utility; +#include maps\mp\zombies\_zm_magicbox; +#include maps\mp\zm_tomb_vo; +#include maps\mp\zombies\_zm_audio; +#include maps\mp\zm_tomb_capture_zones_ffotd; +#include maps\mp\zombies\_zm_spawner; +#include maps\mp\zombies\_zm_perks; +#include maps\mp\zombies\_zm_unitrigger; +#include maps\mp\zombies\_zm_ai_basic; +#include maps\mp\zombies\_zm_stats; +#include maps\mp\zombies\_zm_challenges; +#include maps\mp\zombies\_zm_magicbox_tomb; +#include maps\mp\zombies\_zm_powerups; +#include maps\mp\zm_tomb_capture_zones; + +setup_capture_zones() +{ + spawner_capture_zombie = getent( "capture_zombie_spawner", "targetname" ); + spawner_capture_zombie add_spawn_function( ::capture_zombie_spawn_init ); + a_s_generator = getstructarray( "s_generator", "targetname" ); + registerclientfield( "world", "packapunch_anim", 14000, 3, "int" ); + registerclientfield( "actor", "zone_capture_zombie", 14000, 1, "int" ); + registerclientfield( "scriptmover", "zone_capture_emergence_hole", 14000, 1, "int" ); + registerclientfield( "world", "zc_change_progress_bar_color", 14000, 1, "int" ); + registerclientfield( "world", "zone_capture_hud_all_generators_captured", 14000, 1, "int" ); + registerclientfield( "world", "zone_capture_perk_machine_smoke_fx_always_on", 14000, 1, "int" ); + registerclientfield( "world", "pap_monolith_ring_shake", 14000, 1, "int" ); + + foreach ( struct in a_s_generator ) + { + registerclientfield( "world", struct.script_noteworthy, 14000, 7, "float" ); + registerclientfield( "world", "state_" + struct.script_noteworthy, 14000, 3, "int" ); + registerclientfield( "world", "zone_capture_hud_generator_" + struct.script_int, 14000, 2, "int" ); + registerclientfield( "world", "zone_capture_monolith_crystal_" + struct.script_int, 14000, 1, "int" ); + registerclientfield( "world", "zone_capture_perk_machine_smoke_fx_" + struct.script_int, 14000, 1, "int" ); + } + + flag_wait( "start_zombie_round_logic" ); + level.magic_box_zbarrier_state_func = ::set_magic_box_zbarrier_state; + level.custom_perk_validation = ::check_perk_machine_valid; + level thread track_max_player_zombie_points(); + + foreach ( s_generator in a_s_generator ) + s_generator thread init_capture_zone(); + + register_elements_powered_by_zone_capture_generators(); + setup_perk_machines_not_controlled_by_zone_capture(); + pack_a_punch_init(); + level thread recapture_round_tracker(); + level.zone_capture.recapture_zombies = []; + level.zone_capture.last_zone_captured = undefined; + level.zone_capture.spawn_func_capture_zombie = ::init_capture_zombie; + level.zone_capture.spawn_func_recapture_zombie = ::init_recapture_zombie; + + maps\mp\zombies\_zm_spawner::register_zombie_death_event_callback( ::recapture_zombie_death_func ); + level.custom_derive_damage_refs = ::zone_capture_gib_think; + setup_inaccessible_zombie_attack_points(); + level thread quick_revive_game_type_watcher(); + level thread quick_revive_solo_leave_watcher(); + level thread all_zones_captured_vo(); + flag_set( "capture_zones_init_done" ); + level setclientfield( "zone_capture_perk_machine_smoke_fx_always_on", 1 ); + maps\mp\zm_tomb_capture_zones_ffotd::capture_zone_init_end(); +} + +init_capture_zone() +{ + assert( isdefined( self.script_noteworthy ), "capture zone struct is missing script_noteworthy KVP! This is required for init_capture_zone()" ); + + if ( !isdefined( level.zone_capture ) ) + level.zone_capture = spawnstruct(); + + if ( !isdefined( level.zone_capture.zones ) ) + level.zone_capture.zones = []; + + assert( !isdefined( level.zone_capture.zones[self.script_noteworthy] ), "init_capture_zone() attempting to initialize an existing zone with name '" + self.script_noteworthy + "'" ); + self.n_current_progress = 0; + self.n_last_progress = 0; + self setup_generator_unitrigger(); + self.str_zone = get_zone_from_position( self.origin, 1 ); + self.sndent = spawn( "script_origin", self.origin ); + assert( isdefined( self.script_int ), "script_int KVP is required by init_capture_zone() to identify the objective index, but it's missing on zone '" + self.script_noteworthy + "'" ); + self ent_flag_init( "attacked_by_recapture_zombies" ); + self ent_flag_init( "current_recapture_target_zone" ); + self ent_flag_init( "player_controlled" ); + self ent_flag_init( "zone_contested" ); + self ent_flag_init( "zone_initialized" ); + level.zone_capture.zones[self.script_noteworthy] = self; + self set_zombie_controlled_area( 1 ); + self setup_zombie_attack_points(); + self ent_flag_set( "zone_initialized" ); + self thread wait_for_capture_trigger(); +} + +wait_for_capture_trigger() +{ + while ( true ) + { + self waittill( "start_generator_capture", e_player ); + + if ( !flag( "zone_capture_in_progress" ) ) + { + flag_set( "zone_capture_in_progress" ); + self.purchaser = e_player; + self.generator_cost = get_generator_capture_start_cost(); + e_player minus_to_player_score( self.generator_cost ); + e_player delay_thread( 2.5, ::create_and_play_dialog, "zone_capture", "capture_started" ); + self maps\mp\zm_tomb_capture_zones_ffotd::capture_event_start(); + self thread monitor_capture_zombies(); + self thread activate_capture_zone(); + self ent_flag_wait( "zone_contested" ); + capture_event_handle_ai_limit(); + self ent_flag_waitopen( "zone_contested" ); + self maps\mp\zm_tomb_capture_zones_ffotd::capture_event_end(); + + wait 1; + + self.purchaser = undefined; + } + else + { + flag_wait( "zone_capture_in_progress" ); + flag_waitopen( "zone_capture_in_progress" ); + } + + capture_event_handle_ai_limit(); + + if ( self ent_flag( "player_controlled" ) ) + self ent_flag_waitopen( "player_controlled" ); + } +} + +activate_capture_zone( b_show_emergence_holes = 1 ) +{ + if ( !flag( "recapture_event_in_progress" ) ) + self thread generator_initiated_vo(); + + self.a_emergence_hole_structs = getstructarray( self.target, "targetname" ); + self show_emergence_holes( b_show_emergence_holes ); + + if ( flag( "recapture_event_in_progress" ) && self ent_flag( "current_recapture_target_zone" ) ) + { + flag_wait_any( "generator_under_attack", "recapture_zombies_cleared" ); + + if ( flag( "recapture_zombies_cleared" ) ) + return; + } + + self capture_progress_think(); + self destroy_emergence_holes(); +} + +capture_progress_think() +{ + self init_capture_progress(); + self clear_zone_objective_index(); + self show_zone_capture_objective( 1 ); + self get_zone_objective_index(); + + while ( self ent_flag( "zone_contested" ) ) + { + a_players = get_players(); + a_players_in_capture_zone = self get_players_in_capture_zone(); + + foreach ( player in a_players ) + { + if ( isinarray( a_players_in_capture_zone, player ) ) + { + if ( !flag( "recapture_event_in_progress" ) || !self ent_flag( "current_recapture_target_zone" ) ) + objective_setplayerusing( self.n_objective_index, player ); + + continue; + } + + if ( is_player_valid( player ) ) + objective_clearplayerusing( self.n_objective_index, player ); + } + + self.n_last_progress = self.n_current_progress; + self.n_current_progress += self get_progress_rate( a_players_in_capture_zone.size, a_players.size ); + + if ( self.n_last_progress != self.n_current_progress ) + { + self.n_current_progress = clamp( self.n_current_progress, 0, 100 ); + objective_setprogress( self.n_objective_index, self.n_current_progress / 100 ); + self zone_capture_sound_state_think(); + level setclientfield( self.script_noteworthy, self.n_current_progress / 100 ); + self generator_set_state(); + + if ( !flag( "recapture_event_in_progress" ) || !self ent_flag( "attacked_by_recapture_zombies" ) ) + { + b_set_color_to_white = a_players_in_capture_zone.size > 0; + + if ( !flag( "recapture_event_in_progress" ) && self ent_flag( "current_recapture_target_zone" ) ) + b_set_color_to_white = 1; + + level setclientfield( "zc_change_progress_bar_color", b_set_color_to_white ); + } + + update_objective_on_momentum_change(); + + if ( self.n_current_progress == 0 || self.n_current_progress == 100 && !self ent_flag( "attacked_by_recapture_zombies" ) ) + self ent_flag_clear( "zone_contested" ); + } + + show_zone_capture_debug_info(); + wait 0.1; + } + + self ent_flag_clear( "attacked_by_recapture_zombies" ); + self handle_generator_capture(); + self clear_all_zombie_attack_points_in_zone(); +} + +handle_generator_capture() +{ + level setclientfield( "zc_change_progress_bar_color", 0 ); + self show_zone_capture_objective( 0 ); + + if ( self.n_current_progress == 100 ) + { + self players_capture_zone(); + self kill_all_capture_zombies(); + } + else if ( self.n_current_progress == 0 ) + { + if ( self ent_flag( "player_controlled" ) ) + { + self.sndent stoploopsound( 0.25 ); + self thread generator_deactivated_vo(); + self.is_playing_audio = 0; + + foreach ( player in get_players() ) + { + player maps\mp\zombies\_zm_stats::increment_client_stat( "tomb_generator_lost", 0 ); + player maps\mp\zombies\_zm_stats::increment_player_stat( "tomb_generator_lost" ); + } + } + + self set_zombie_controlled_area(); + + if ( flag( "recapture_event_in_progress" ) && get_captured_zone_count() > 0 ) + { + + } + else + self kill_all_capture_zombies(); + } + + if ( get_contested_zone_count() == 0 ) + flag_clear( "zone_capture_in_progress" ); +} + +players_capture_zone() +{ + self.sndent playsound( "zmb_capturezone_success" ); + self.sndent stoploopsound( 0.25 ); + reward_players_in_capture_zone(); + wait_network_frame(); + + if ( !flag( "recapture_event_in_progress" ) && !self ent_flag( "player_controlled" ) ) + self thread zone_capture_complete_vo(); + + self set_player_controlled_area(); + wait_network_frame(); + playfx( level._effect["capture_complete"], self.origin ); + level thread sndplaygeneratormusicstinger(); +} + +reward_players_in_capture_zone() +{ + b_challenge_exists = maps\mp\zombies\_zm_challenges::challenge_exists( "zc_zone_captures" ); + + if ( !self ent_flag( "player_controlled" ) ) + { + foreach ( player in get_players_in_capture_zone() ) + { + if ( isdefined( self.purchaser ) && self.purchaser == player ) + self refund_generator_cost_if_player_captured_it( player ); + + player notify( "completed_zone_capture" ); + player maps\mp\zombies\_zm_score::player_add_points( "bonus_points_powerup", 200 ); + + if ( b_challenge_exists ) + player maps\mp\zombies\_zm_challenges::increment_stat( "zc_zone_captures" ); + + player maps\mp\zombies\_zm_stats::increment_client_stat( "tomb_generator_captured", 0 ); + player maps\mp\zombies\_zm_stats::increment_player_stat( "tomb_generator_captured" ); + } + } +} + +recapture_zombie_death_func() +{ + if ( isdefined( self.is_recapture_zombie ) && self.is_recapture_zombie ) + { + level.recapture_zombies_killed++; + + if ( isdefined( self.attacker ) && isplayer( self.attacker ) && level.recapture_zombies_killed == get_recapture_zombies_needed() ) + { + self.attacker thread delay_thread( 2, ::create_and_play_dialog, "zone_capture", "recapture_prevented" ); + + foreach ( player in get_players() ) + { + player maps\mp\zombies\_zm_stats::increment_client_stat( "tomb_generator_defended", 0 ); + player maps\mp\zombies\_zm_stats::increment_player_stat( "tomb_generator_defended" ); + } + } + + if ( level.recapture_zombies_killed == get_recapture_zombies_needed() && is_true( level.b_is_first_generator_attack ) ) + self drop_max_ammo_at_death_location(); + } +} + +recapture_round_tracker() +{ + n_next_recapture_round = 10; + + while ( true ) + { + level waittill_any( "between_round_over", "force_recapture_start" ); + + if ( level.round_number >= n_next_recapture_round && !flag( "zone_capture_in_progress" ) && get_captured_zone_count() >= get_player_controlled_zone_count_for_recapture() ) + { + n_next_recapture_round = level.round_number + randomintrange( 3, 6 ); + level thread recapture_round_start(); + } + } +} + +recapture_round_start() +{ + flag_set( "recapture_event_in_progress" ); + flag_clear( "recapture_zombies_cleared" ); + flag_clear( "generator_under_attack" ); + level.recapture_zombies_killed = 0; + level.b_is_first_generator_attack = 1; + s_recapture_target_zone = undefined; + capture_event_handle_ai_limit(); + recapture_round_audio_starts(); + + while ( !flag( "recapture_zombies_cleared" ) && get_captured_zone_count() > 0 ) + { + s_recapture_target_zone = get_recapture_zone( s_recapture_target_zone ); + level.zone_capture.recapture_target = s_recapture_target_zone.script_noteworthy; + s_recapture_target_zone maps\mp\zm_tomb_capture_zones_ffotd::recapture_event_start(); + + if ( level.b_is_first_generator_attack ) + s_recapture_target_zone thread monitor_recapture_zombies(); + + set_recapture_zombie_attack_target( s_recapture_target_zone ); + s_recapture_target_zone thread generator_under_attack_warnings(); + s_recapture_target_zone ent_flag_set( "current_recapture_target_zone" ); + s_recapture_target_zone thread hide_zone_objective_while_recapture_group_runs_to_next_generator( level.b_is_first_generator_attack ); + s_recapture_target_zone activate_capture_zone( level.b_is_first_generator_attack ); + s_recapture_target_zone ent_flag_clear( "attacked_by_recapture_zombies" ); + s_recapture_target_zone ent_flag_clear( "current_recapture_target_zone" ); + + if ( level.b_is_first_generator_attack && !s_recapture_target_zone ent_flag( "player_controlled" ) ) + delay_thread( 3, ::broadcast_vo_category_to_team, "recapture_started" ); + + level.b_is_first_generator_attack = 0; + s_recapture_target_zone maps\mp\zm_tomb_capture_zones_ffotd::recapture_event_end(); + wait 0.05; + } + + //if ( s_recapture_target_zone.n_current_progress == 0 || s_recapture_target_zone.n_current_progress == 100 ) + // s_recapture_target_zone handle_generator_capture(); + + capture_event_handle_ai_limit(); + kill_all_recapture_zombies(); + recapture_round_audio_ends(); + flag_clear( "recapture_event_in_progress" ); + flag_clear( "generator_under_attack" ); +} \ No newline at end of file diff --git a/scripts/zm/zm_tomb/zm_tomb_reimagined.gsc b/scripts/zm/zm_tomb/zm_tomb_reimagined.gsc index 429b4813..9b2dca38 100644 --- a/scripts/zm/zm_tomb/zm_tomb_reimagined.gsc +++ b/scripts/zm/zm_tomb/zm_tomb_reimagined.gsc @@ -8,6 +8,7 @@ #include scripts\zm\replaced\zm_tomb_quest_elec; #include scripts\zm\replaced\zm_tomb_quest_fire; #include scripts\zm\replaced\zm_tomb_quest_ice; +#include scripts\zm\replaced\zm_tomb_capture_zones; #include scripts\zm\replaced\zm_tomb_challenges; #include scripts\zm\replaced\zm_tomb_craftables; #include scripts\zm\replaced\zm_tomb_dig; @@ -35,6 +36,7 @@ main() replaceFunc(maps\mp\zm_tomb_ee_main_step_2::create_robot_head_trigger, scripts\zm\replaced\zm_tomb_ee_main_step_2::create_robot_head_trigger); replaceFunc(maps\mp\zm_tomb_ee_main_step_2::remove_plinth, scripts\zm\replaced\zm_tomb_ee_main_step_2::remove_plinth); replaceFunc(maps\mp\zm_tomb_ee_main_step_3::fire_link_cooldown, scripts\zm\replaced\zm_tomb_ee_main_step_3::fire_link_cooldown); + replaceFunc(maps\mp\zm_tomb_capture_zones::setup_capture_zones, scripts\zm\replaced\zm_tomb_capture_zones::setup_capture_zones); replaceFunc(maps\mp\zm_tomb_challenges::challenges_init, scripts\zm\replaced\zm_tomb_challenges::challenges_init); replaceFunc(maps\mp\zm_tomb_craftables::init_craftables, scripts\zm\replaced\zm_tomb_craftables::init_craftables); replaceFunc(maps\mp\zm_tomb_craftables::include_craftables, scripts\zm\replaced\zm_tomb_craftables::include_craftables);