diff --git a/README.md b/README.md index 0c7aceb0..ac19065c 100644 --- a/README.md +++ b/README.md @@ -591,6 +591,7 @@ * Quest: can enter the plane in afterlife without Weasel * Quest: if Weasel is the only player in the game, the cycle breaks immediately after reviving yourself on the Golden Gate Bridge * Quest: if Weasel is not in the game, the cycle continues immediately immediately after everyone revives themselves on the Golden Gate Bridge +* Quest: showdown target waypoint shows offscreen * Grief: added Smoke Grenades to the Mystery Box * Grief: added Richtofen's Head meat powerup model * Grief: Tower Trap targets and stuns players diff --git a/scripts/zm/replaced/_zm_chugabud.gsc b/scripts/zm/replaced/_zm_chugabud.gsc index 315e6456..b7891c71 100644 --- a/scripts/zm/replaced/_zm_chugabud.gsc +++ b/scripts/zm/replaced/_zm_chugabud.gsc @@ -29,7 +29,6 @@ chugabud_corpse_revive_icon( player ) self endon( "death" ); height_offset = 30; index = player.clientid; - self.revive_waypoint_origin = spawn( "script_model", self.origin + (0, 0, height_offset) ); self.revive_waypoint_origin setmodel( "tag_origin" ); self.revive_waypoint_origin linkto( self ); @@ -75,7 +74,7 @@ chugabud_corpse_cleanup( corpse, was_revived ) if ( isdefined( corpse.revive_waypoint_origin ) ) { - corpse.revive_waypoint_origin destroy(); + corpse.revive_waypoint_origin delete(); corpse.revive_waypoint_origin = undefined; } diff --git a/scripts/zm/replaced/zm_prison_sq_final.gsc b/scripts/zm/replaced/zm_prison_sq_final.gsc index 22375b21..82085446 100644 --- a/scripts/zm/replaced/zm_prison_sq_final.gsc +++ b/scripts/zm/replaced/zm_prison_sq_final.gsc @@ -137,4 +137,305 @@ final_flight_trigger() return; } } +} + +final_flight_player_thread() +{ + self endon( "death_or_disconnect" ); + self.on_a_plane = 1; + self.dontspeak = 1; + self setclientfieldtoplayer( "isspeaking", 1 ); + + if ( !( isdefined( self.afterlife ) && self.afterlife ) ) + { + self.keep_perks = 1; + self afterlife_remove(); + self.afterlife = 1; + self thread afterlife_laststand(); + + self waittill( "player_fake_corpse_created" ); + } + + self afterlife_infinite_mana( 1 ); + level.final_flight_activated = 1; + level.final_flight_players[level.final_flight_players.size] = self; + a_nml_teleport_targets = []; + + for ( i = 1; i < 6; i++ ) + a_nml_teleport_targets[i - 1] = getstruct( "nml_telepoint_" + i, "targetname" ); + + self.n_passenger_index = level.final_flight_players.size; + a_players = []; + a_players = getplayers(); + + if ( a_players.size == 1 ) + self.n_passenger_index = 1; + + m_plane_craftable = getent( "plane_craftable", "targetname" ); + m_plane_about_to_crash = getent( "plane_about_to_crash", "targetname" ); + m_plane_about_to_crash ghost(); + veh_plane_flyable = getent( "plane_flyable", "targetname" ); + veh_plane_flyable show(); + flag_set( "plane_boarded" ); + t_plane_fly = getent( "plane_fly_trigger", "targetname" ); + str_hint_string = "BOARD FINAL FLIGHT"; + t_plane_fly sethintstring( str_hint_string ); + self playerlinktodelta( m_plane_craftable, "tag_player_crouched_" + ( self.n_passenger_index + 1 ) ); + self allowcrouch( 1 ); + self allowstand( 0 ); + self clientnotify( "sndFFCON" ); + flag_wait( "plane_departed" ); + level notify( "sndStopBrutusLoop" ); + self clientnotify( "sndPS" ); + self playsoundtoplayer( "zmb_plane_takeoff", self ); + level thread maps\mp\zombies\_zm_audio::sndmusicstingerevent( "plane_takeoff", self ); + m_plane_craftable ghost(); + self playerlinktodelta( veh_plane_flyable, "tag_player_crouched_" + ( self.n_passenger_index + 1 ) ); + self setclientfieldtoplayer( "effects_escape_flight", 1 ); + flag_wait( "plane_approach_bridge" ); + self thread maps\mp\zm_alcatraz_sq::snddelayedimp(); + self setclientfieldtoplayer( "effects_escape_flight", 2 ); + self unlink(); + self playerlinktoabsolute( veh_plane_flyable, "tag_player_crouched_" + ( self.n_passenger_index + 1 ) ); + flag_wait( "plane_zapped" ); + flag_set( "activate_player_zone_bridge" ); + self playsoundtoplayer( "zmb_plane_fall", self ); + self setclientfieldtoplayer( "effects_escape_flight", 3 ); + self.dontspeak = 1; + self setclientfieldtoplayer( "isspeaking", 1 ); + self playerlinktodelta( m_plane_about_to_crash, "tag_player_crouched_" + ( self.n_passenger_index + 1 ), 1, 0, 0, 0, 0, 1 ); + flag_wait( "plane_crashed" ); + self thread fadetoblackforxsec( 0, 2, 0, 0.5, "black" ); + self unlink(); + self allowstand( 1 ); + self setstance( "stand" ); + self allowcrouch( 0 ); + flag_clear( "spawn_zombies" ); + self setorigin( a_nml_teleport_targets[self.n_passenger_index].origin ); + e_poi = getstruct( "plane_crash_poi", "targetname" ); + vec_to_target = e_poi.origin - self.origin; + vec_to_target = vectortoangles( vec_to_target ); + vec_to_target = ( 0, vec_to_target[1], 0 ); + self setplayerangles( vec_to_target ); + n_shellshock_duration = 5; + self shellshock( "explosion", n_shellshock_duration ); + self.on_a_plane = 0; + stage_final(); +} + +stage_final() +{ + level notify( "stage_final" ); + level endon( "stage_final" ); + b_everyone_alive = 0; + + while ( isdefined( b_everyone_alive ) && !b_everyone_alive ) + { + b_everyone_alive = 1; + a_players = getplayers(); + + foreach ( player in a_players ) + { + if ( isdefined( player.afterlife ) && player.afterlife ) + { + b_everyone_alive = 0; + wait 0.05; + break; + } + } + } + + level._should_skip_ignore_player_logic = ::final_showdown_zombie_logic; + flag_set( "spawn_zombies" ); + array_func( getplayers(), maps\mp\zombies\_zm_afterlife::afterlife_remove ); + p_weasel = undefined; + a_player_team = []; + a_players = getplayers(); + + foreach ( player in a_players ) + { + player.dontspeak = 1; + player setclientfieldtoplayer( "isspeaking", 1 ); + + if ( player.character_name == "Arlington" ) + { + p_weasel = player; + continue; + } + + a_player_team[a_player_team.size] = player; + } + + if ( isdefined( p_weasel ) && a_player_team.size > 0 ) + { + level.longregentime = 1000000; + level.playerhealth_regularregendelay = 1000000; + p_weasel.team = level.zombie_team; + p_weasel.pers["team"] = level.zombie_team; + p_weasel.sessionteam = level.zombie_team; + p_weasel.maxhealth = a_player_team.size * 2000; + p_weasel.health = p_weasel.maxhealth; + + foreach ( player in a_player_team ) + { + player.maxhealth = 2000; + player.health = player.maxhealth; + } + + level thread final_showdown_track_weasel( p_weasel ); + level thread final_showdown_track_team( a_player_team ); + n_spawns_needed = 2; + + for ( i = n_spawns_needed; i > 0; i-- ) + maps\mp\zombies\_zm_ai_brutus::brutus_spawn_in_zone( "zone_golden_gate_bridge", 1 ); + + level thread final_battle_vo( p_weasel, a_player_team ); + level notify( "pop_goes_the_weasel_achieved" ); + + level waittill( "showdown_over" ); + } + else if ( isdefined( p_weasel ) ) + level.winner = "weasel"; + else + level.winner = "team"; + + level clientnotify( "sndSQF" ); + level.brutus_respawn_after_despawn = 0; + level thread clean_up_final_brutuses(); + wait 2; + + if ( level.winner == "weasel" ) + { + a_players = getplayers(); + + foreach ( player in a_players ) + { + player freezecontrols( 1 ); + player maps\mp\zombies\_zm_stats::increment_client_stat( "prison_ee_good_ending", 0 ); + player thread fadetoblackforxsec( 0, 5, 0.5, 0, "white" ); + player create_ending_message( &"ZM_PRISON_GOOD" ); + player.client_hint.sort = 55; + player.client_hint.color = ( 0, 0, 0 ); + playsoundatposition( "zmb_quest_final_white_good", ( 0, 0, 0 ) ); + level.sndgameovermusicoverride = "game_over_final_good"; + } + + level.custom_intermission = ::player_intermission_bridge; + } + else + { + a_players = getplayers(); + + foreach ( player in a_players ) + { + player freezecontrols( 1 ); + player maps\mp\zombies\_zm_stats::increment_client_stat( "prison_ee_bad_ending", 0 ); + player thread fadetoblackforxsec( 0, 5, 0.5, 0, "white" ); + player create_ending_message( &"ZM_PRISON_BAD" ); + player.client_hint.sort = 55; + player.client_hint.color = ( 0, 0, 0 ); + playsoundatposition( "zmb_quest_final_white_bad", ( 0, 0, 0 ) ); + level.sndgameovermusicoverride = "game_over_final_bad"; + } + } + + wait 5; + a_players = getplayers(); + + foreach ( player in a_players ) + { + if ( isdefined( player.client_hint ) ) + player thread destroy_tutorial_message(); + + if ( isdefined( player.revivetrigger ) ) + { + player thread revive_success( player, 0 ); + player cleanup_suicide_hud(); + } + + if ( isdefined( player ) ) + player ghost(); + } + + if ( isdefined( p_weasel ) ) + { + p_weasel.team = "allies"; + p_weasel.pers["team"] = "allies"; + p_weasel.sessionteam = "allies"; + p_weasel ghost(); + } + + level notify( "end_game" ); +} + +final_battle_vo( p_weasel, a_player_team ) +{ + level endon( "showdown_over" ); + wait 10; + a_players = arraycopy( a_player_team ); + player = a_players[randomintrange( 0, a_players.size )]; + arrayremovevalue( a_players, player ); + + if ( a_players.size > 0 ) + player_2 = a_players[randomintrange( 0, a_players.size )]; + + if ( isdefined( player ) ) + player final_battle_reveal(); + + wait 3; + + if ( isdefined( p_weasel ) ) + p_weasel playsoundontag( "vox_plr_3_end_scenario_0", "J_Head" ); + + wait 1; + + foreach ( player in a_player_team ) + { + level thread final_showdown_create_icon( player, p_weasel ); + level thread final_showdown_create_icon( p_weasel, player ); + } + + wait 10; + + if ( isdefined( player_2 ) ) + player_2 playsoundontag( "vox_plr_" + player_2.characterindex + "_end_scenario_1", "J_Head" ); + else if ( isdefined( player ) ) + player playsoundontag( "vox_plr_" + player.characterindex + "_end_scenario_1", "J_Head" ); + + wait 4; + + if ( isdefined( p_weasel ) ) + { + p_weasel playsoundontag( "vox_plr_3_end_scenario_1", "J_Head" ); + p_weasel.dontspeak = 0; + p_weasel setclientfieldtoplayer( "isspeaking", 0 ); + } + + foreach ( player in a_player_team ) + { + player.dontspeak = 0; + player setclientfieldtoplayer( "isspeaking", 0 ); + } +} + +final_showdown_create_icon( player, enemy ) +{ + height_offset = 72; + waypoint_origin = spawn( "script_model", enemy.origin + (0, 0, height_offset) ); + waypoint_origin setmodel( "tag_origin" ); + waypoint_origin linkto( enemy ); + + hud_elem = newclienthudelem( player ); + hud_elem.alpha = 1; + hud_elem.archived = 1; + hud_elem.foreground = 1; + hud_elem.hidewheninmenu = 1; + hud_elem.color = (1, 0, 0); + hud_elem setwaypoint( 1, "waypoint_kill_red" ); + hud_elem settargetent( waypoint_origin ); + + waittill_any_ents( level, "showdown_over", enemy, "disconnect" ); + + waypoint_origin delete(); + hud_elem destroy(); } \ No newline at end of file