//checked includes changed to match cerberus output #include maps/mp/zombies/_zm_perks; #include maps/mp/zombies/_zm_chugabud; #include maps/mp/zombies/_zm_equipment; #include maps/mp/zombies/_zm_buildables; #include maps/mp/gametypes_zm/_gameobjects; #include maps/mp/zombies/_zm_pers_upgrades_functions; #include maps/mp/zombies/_zm_stats; #include maps/mp/_demo; #include maps/mp/gametypes_zm/_hud_util; #include maps/mp/zombies/_zm_utility; #include maps/mp/_utility; #include common_scripts/utility; laststand_global_init() //checked matches cerberus output { level.const_laststand_getup_count_start = 0; level.const_laststand_getup_bar_start = 0.5; level.const_laststand_getup_bar_regen = 0.0025; level.const_laststand_getup_bar_damage = 0.1; } init() //checked matches cerberus output //checked matches beta dump { if ( level.script == "frontend" ) { return; } laststand_global_init(); level.revive_tool = "syrette_zm"; precacheitem( level.revive_tool ); precachestring( &"ZOMBIE_BUTTON_TO_REVIVE_PLAYER" ); precachestring( &"ZOMBIE_PLAYER_NEEDS_TO_BE_REVIVED" ); precachestring( &"ZOMBIE_PLAYER_IS_REVIVING_YOU" ); precachestring( &"ZOMBIE_REVIVING" ); if ( !isDefined( level.laststandpistol ) ) { level.laststandpistol = "m1911"; precacheitem( level.laststandpistol ); } level thread revive_hud_think(); level.primaryprogressbarx = 0; level.primaryprogressbary = 110; level.primaryprogressbarheight = 4; level.primaryprogressbarwidth = 120; level.primaryprogressbary_ss = 280; if ( getDvar( "revive_trigger_radius" ) == "" ) { setdvar( "revive_trigger_radius", "40" ); } level.laststandgetupallowed = 0; } player_is_in_laststand() //checked changed to match cerberus output //changed at own discretion { if ( !is_true( self.no_revive_trigger ) && isDefined( self.revivetrigger ) ) { return 1; } if ( is_true( self.laststand ) ) { return 1; } return 0; } player_num_in_laststand() //checked changed to match cerberus output //checked matches beta dump { num = 0; players = get_players(); for ( i = 0; i < players.size; i++ ) { if ( players[ i ] player_is_in_laststand() ) { num++; } } return num; } player_all_players_in_laststand() //checked changed at own discretion //checked matches beta dump { if ( player_num_in_laststand() == get_players().size ) { return 1; } return 0; } player_any_player_in_laststand() //checked changed at own discretion //checked matches beta dump { if ( player_num_in_laststand() > 0 ) { return 1; } return 0; } player_last_stand_stats( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) //checked matches cerberus output { if ( isDefined( attacker ) && isplayer( attacker ) && attacker != self ) { if ( level.gametype == "zcleansed" ) { maps/mp/_demo::bookmark( "kill", getTime(), self, attacker, 0, einflictor ); } if ( level.gametype == "zcleansed" ) { if ( isDefined( attacker.is_zombie ) && !attacker.is_zombie ) { attacker.kills++; } else { attacker.downs++; } } else { attacker.kills++; } attacker maps/mp/zombies/_zm_stats::increment_client_stat( "kills" ); attacker maps/mp/zombies/_zm_stats::increment_player_stat( "kills" ); if ( isDefined( sweapon ) ) { dmgweapon = sweapon; if ( is_alt_weapon( dmgweapon ) ) { dmgweapon = weaponaltweaponname( dmgweapon ); } attacker addweaponstat( dmgweapon, "kills", 1 ); } if ( is_headshot( sweapon, shitloc, smeansofdeath ) ) { attacker.headshots++; attacker maps/mp/zombies/_zm_stats::increment_client_stat( "headshots" ); attacker addweaponstat( sweapon, "headshots", 1 ); attacker maps/mp/zombies/_zm_stats::increment_player_stat( "headshots" ); } } self increment_downed_stat(); if ( flag( "solo_game" ) && !self.lives && getnumconnectedplayers() < 2 ) { self maps/mp/zombies/_zm_stats::increment_client_stat( "deaths" ); self maps/mp/zombies/_zm_stats::increment_player_stat( "deaths" ); self maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_jugg_player_death_stat(); } } increment_downed_stat() //checked matches cerberus output { if ( level.gametype != "zcleansed" ) { self.downs++; } self maps/mp/zombies/_zm_stats::increment_client_stat( "downs" ); self add_weighted_down(); self maps/mp/zombies/_zm_stats::increment_player_stat( "downs" ); zonename = self get_current_zone(); if ( !isDefined( zonename ) ) { zonename = ""; } self recordplayerdownzombies( zonename ); } playerlaststand( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) //checked matches cerberus output //checked changed to match beta dump { self notify( "entering_last_stand" ); if ( isDefined( level._game_module_player_laststand_callback ) ) { self [[ level._game_module_player_laststand_callback ]]( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ); } if ( self player_is_in_laststand() ) { return; } if ( is_true( self.in_zombify_call ) ) { return; } self thread player_last_stand_stats( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ); if ( isDefined( level.playerlaststand_func ) ) { [[ level.playerlaststand_func ]]( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ); } self.health = 1; self.laststand = 1; self.ignoreme = 1; self thread maps/mp/gametypes_zm/_gameobjects::onplayerlaststand(); self thread maps/mp/zombies/_zm_buildables::onplayerlaststand(); if ( !is_true( self.no_revive_trigger ) ) { self revive_trigger_spawn(); } else { self undolaststand(); } if ( is_true( self.is_zombie ) ) { self takeallweapons(); if ( isDefined( attacker ) && isplayer( attacker ) && attacker != self ) { attacker notify( "killed_a_zombie_player", eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ); } } else { self laststand_disable_player_weapons(); self laststand_give_pistol(); } if ( is_true( level.playerSuicideAllowed ) && get_players().size > 1 ) { if ( !isDefined( level.canplayersuicide ) || self [[ level.canplayersuicide ]]() ) { self thread suicide_trigger_spawn(); } } if ( isDefined( self.disabled_perks ) ) { self.disabled_perks = []; } if ( level.laststandgetupallowed ) { self thread laststand_getup(); } else { bleedout_time = getDvarFloat( "player_lastStandBleedoutTime" ); self thread laststand_bleedout( bleedout_time ); } if ( level.gametype != "zcleansed" ) { maps/mp/_demo::bookmark( "zm_player_downed", getTime(), self ); } self notify( "player_downed" ); self thread refire_player_downed(); self thread cleanup_laststand_on_disconnect(); } refire_player_downed() //checked matches cerberus output { self endon( "player_revived" ); self endon( "death" ); self endon( "disconnect" ); wait 1; if ( self.num_perks ) { self notify( "player_downed" ); } } laststand_allowed( sweapon, smeansofdeath, shitloc ) //checked matches cerberus output { if ( level.laststandpistol == "none" ) { return 0; } return 1; } laststand_disable_player_weapons() //checked partially changed to match cerberus output //did not change while loop to for loop to prevent infinite loop bug due to continue { weaponinventory = self getweaponslist( 1 ); self.lastactiveweapon = self getcurrentweapon(); if ( self isthrowinggrenade() && is_offhand_weapon( self.lastactiveweapon ) ) { primaryweapons = self getweaponslistprimaries(); if ( isDefined( primaryweapons ) && primaryweapons.size > 0 ) { self.lastactiveweapon = primaryweapons[ 0 ]; self switchtoweaponimmediate( self.lastactiveweapon ); } } self setlaststandprevweap( self.lastactiveweapon ); self.laststandpistol = undefined; self.hadpistol = 0; if ( isDefined( self.weapon_taken_by_losing_specialty_additionalprimaryweapon ) && self.lastactiveweapon == self.weapon_taken_by_losing_specialty_additionalprimaryweapon ) { self.lastactiveweapon = "none"; self.weapon_taken_by_losing_specialty_additionalprimaryweapon = undefined; } i = 0; while ( i < weaponinventory.size ) { weapon = weaponinventory[ i ]; class = weaponclass( weapon ); if ( issubstr( weapon, "knife_ballistic_" ) ) { class = "knife"; } if ( ( class == "pistol" || class == "pistol spread" ) && !isDefined( self.laststandpistol ) || class == "pistolspread" && !isDefined( self.laststandpistol ) ) { self.laststandpistol = weapon; self.hadpistol = 1; } if ( weapon == "syrette_zm" ) { self maps/mp/zombies/_zm_stats::increment_client_stat( "failed_sacrifices" ); self maps/mp/zombies/_zm_stats::increment_player_stat( "failed_sacrifices" ); } else if ( is_zombie_perk_bottle( weapon ) ) { self takeweapon( weapon ); self.lastactiveweapon = "none"; i++; continue; } if ( isDefined( get_gamemode_var( "item_meat_name" ) ) ) { if ( weapon == get_gamemode_var( "item_meat_name" ) ) { self takeweapon( weapon ); self.lastactiveweapon = "none"; i++; continue; } } i++; } if ( isDefined( self.hadpistol ) && self.hadpistol == 1 && isDefined( level.zombie_last_stand_pistol_memory ) ) { self [[ level.zombie_last_stand_pistol_memory ]](); } if ( !isDefined( self.laststandpistol ) ) { self.laststandpistol = level.laststandpistol; } self disableweaponcycling(); self notify( "weapons_taken_for_last_stand" ); } laststand_enable_player_weapons() //checked matches cerberus output { if ( !is_true( self.hadpistol ) && isDefined( self.laststandpistol ) ) { self takeweapon( self.laststandpistol ); } if ( isDefined( self.hadpistol ) && self.hadpistol == 1 && isDefined( level.zombie_last_stand_ammo_return ) ) { [[ level.zombie_last_stand_ammo_return ]](); } self enableweaponcycling(); self enableoffhandweapons(); if ( isDefined( self.lastactiveweapon ) && self.lastactiveweapon != "none" && self hasweapon( self.lastactiveweapon ) && !is_placeable_mine( self.lastactiveweapon ) && !is_equipment( self.lastactiveweapon ) ) { self switchtoweapon( self.lastactiveweapon ); } else { primaryweapons = self getweaponslistprimaries(); if ( isDefined( primaryweapons ) && primaryweapons.size > 0 ) { self switchtoweapon( primaryweapons[ 0 ] ); } } } laststand_clean_up_on_disconnect( playerbeingrevived, revivergun ) //checked matches cerberus output { self endon( "do_revive_ended_normally" ); revivetrigger = playerbeingrevived.revivetrigger; playerbeingrevived waittill( "disconnect" ); if ( isDefined( revivetrigger ) ) { revivetrigger delete(); } self cleanup_suicide_hud(); if ( isDefined( self.reviveprogressbar ) ) { self.reviveprogressbar destroyelem(); } if ( isDefined( self.revivetexthud ) ) { self.revivetexthud destroy(); } self revive_give_back_weapons( revivergun ); } laststand_clean_up_reviving_any( playerbeingrevived ) //checked changed to match cerberus output { self endon( "do_revive_ended_normally" ); playerbeingrevived waittill_any( "disconnect", "zombified", "stop_revive_trigger" ); self.is_reviving_any--; if ( self.is_reviving_any < 0 ) { self.is_reviving_any = 0; } } laststand_give_pistol() //checked changed to match cerberus output { /* /# assert( isDefined( self.laststandpistol ) ); #/ /# assert( self.laststandpistol != "none" ); #/ */ if ( isDefined( level.zombie_last_stand ) ) { [[ level.zombie_last_stand ]](); } else { self giveweapon( self.laststandpistol ); self givemaxammo( self.laststandpistol ); self switchtoweapon( self.laststandpistol ); } } laststand_bleedout( delay ) //checked changed to match cerberus output { self endon( "player_revived" ); self endon( "player_suicide" ); self endon( "zombified" ); self endon( "disconnect" ); if ( is_true( self.is_zombie ) || is_true( self.no_revive_trigger ) ) { self notify( "bled_out" ); wait_network_frame(); self bleed_out(); return; } setclientsysstate( "lsm", "1", self ); self.bleedout_time = delay; while ( self.bleedout_time > int( delay * 0.5 ) ) { self.bleedout_time -= 1; wait 1; } visionsetlaststand( "zombie_death", delay * 0.5 ); while ( self.bleedout_time > 0 ) { self.bleedout_time -= 1; wait 1; } while ( isDefined( self.revivetrigger ) && isDefined( self.revivetrigger.beingrevived ) && self.revivetrigger.beingrevived == 1 ) { wait 0.1; } self notify( "bled_out" ); wait_network_frame(); self bleed_out(); } bleed_out() //checked changed to match cerberus output { self cleanup_suicide_hud(); if ( isDefined( self.revivetrigger ) ) { self.revivetrigger delete(); } self.revivetrigger = undefined; setclientsysstate( "lsm", "0", self ); self maps/mp/zombies/_zm_stats::increment_client_stat( "deaths" ); self maps/mp/zombies/_zm_stats::increment_player_stat( "deaths" ); self maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_jugg_player_death_stat(); self recordplayerdeathzombies(); self maps/mp/zombies/_zm_equipment::equipment_take(); if ( level.gametype != "zcleansed" ) { maps/mp/_demo::bookmark( "zm_player_bledout", getTime(), self, undefined, 1 ); } level notify( "bleed_out", self.characterindex ); self undolaststand(); if ( is_true( level.is_zombie_level ) ) { self thread [[ level.player_becomes_zombie ]](); } if ( is_true( level.is_specops_level ) ) { self thread [[ level.spawnspectator ]](); } else { self.ignoreme = 0; } } cleanup_suicide_hud() //checked matches cerberus output { if ( isDefined( self.suicideprompt ) ) { self.suicideprompt destroy(); } self.suicideprompt = undefined; } clean_up_suicide_hud_on_end_game() //checked matches cerberus output { self endon( "disconnect" ); self endon( "zombified" ); self endon( "stop_revive_trigger" ); self endon( "player_revived" ); self endon( "bled_out" ); level waittill_any( "end_game", "stop_suicide_trigger" ); self cleanup_suicide_hud(); if ( isDefined( self.suicidetexthud ) ) { self.suicidetexthud destroy(); } if ( isDefined( self.suicideprogressbar ) ) { self.suicideprogressbar destroyelem(); } } clean_up_suicide_hud_on_bled_out() //checked matches cerberus output { self endon( "disconnect" ); self endon( "zombified" ); self endon( "stop_revive_trigger" ); self waittill_any( "bled_out", "player_revived", "fake_death" ); self cleanup_suicide_hud(); if ( isDefined( self.suicideprogressbar ) ) { self.suicideprogressbar destroyelem(); } if ( isDefined( self.suicidetexthud ) ) { self.suicidetexthud destroy(); } } suicide_trigger_spawn() //checked matches cerberus output { radius = getDvarInt( "revive_trigger_radius" ); self.suicideprompt = newclienthudelem( self ); self.suicideprompt.alignx = "center"; self.suicideprompt.aligny = "middle"; self.suicideprompt.horzalign = "center"; self.suicideprompt.vertalign = "bottom"; self.suicideprompt.y = -170; if ( self issplitscreen() ) { self.suicideprompt.y = -132; } self.suicideprompt.foreground = 1; self.suicideprompt.font = "default"; self.suicideprompt.fontscale = 1.5; self.suicideprompt.alpha = 1; self.suicideprompt.color = ( 1, 1, 1 ); self.suicideprompt.hidewheninmenu = 1; self thread suicide_trigger_think(); } suicide_trigger_think() //checked changed to match cerberus output { self endon( "disconnect" ); self endon( "zombified" ); self endon( "stop_revive_trigger" ); self endon( "player_revived" ); self endon( "bled_out" ); self endon( "fake_death" ); level endon( "end_game" ); level endon( "stop_suicide_trigger" ); self thread clean_up_suicide_hud_on_end_game(); self thread clean_up_suicide_hud_on_bled_out(); while ( self usebuttonpressed() ) { wait 1; } if ( !isDefined( self.suicideprompt ) ) { return; } while ( 1 ) { wait 0.1; if ( !isDefined( self.suicideprompt ) ) { continue; } self.suicideprompt settext( &"ZOMBIE_BUTTON_TO_SUICIDE" ); if ( !self is_suiciding() ) { continue; } self.pre_suicide_weapon = self getcurrentweapon(); self giveweapon( level.suicide_weapon ); self switchtoweapon( level.suicide_weapon ); duration = self docowardswayanims(); suicide_success = suicide_do_suicide( duration ); self.laststand = undefined; self takeweapon( level.suicide_weapon ); if ( suicide_success ) { self notify( "player_suicide" ); wait_network_frame(); self maps/mp/zombies/_zm_stats::increment_client_stat( "suicides" ); self bleed_out(); return; } self switchtoweapon( self.pre_suicide_weapon ); self.pre_suicide_weapon = undefined; } } suicide_do_suicide( duration ) //checked matches cerberus output { level endon( "end_game" ); level endon( "stop_suicide_trigger" ); suicidetime = duration; timer = 0; suicided = 0; self.suicideprompt settext( "" ); if ( !isDefined( self.suicideprogressbar ) ) { self.suicideprogressbar = self createprimaryprogressbar(); } if ( !isDefined( self.suicidetexthud ) ) { self.suicidetexthud = newclienthudelem( self ); } self.suicideprogressbar updatebar( 0.01, 1 / suicidetime ); self.suicidetexthud.alignx = "center"; self.suicidetexthud.aligny = "middle"; self.suicidetexthud.horzalign = "center"; self.suicidetexthud.vertalign = "bottom"; self.suicidetexthud.y = -173; if ( self issplitscreen() ) { self.suicidetexthud.y = -147; } self.suicidetexthud.foreground = 1; self.suicidetexthud.font = "default"; self.suicidetexthud.fontscale = 1.8; self.suicidetexthud.alpha = 1; self.suicidetexthud.color = ( 1, 1, 1 ); self.suicidetexthud.hidewheninmenu = 1; self.suicidetexthud settext( &"ZOMBIE_SUICIDING" ); while ( self is_suiciding() ) { wait 0.05; timer += 0.05; if ( timer >= suicidetime ) { suicided = 1; break; } } if ( isDefined( self.suicideprogressbar ) ) { self.suicideprogressbar destroyelem(); } if ( isDefined( self.suicidetexthud ) ) { self.suicidetexthud destroy(); } if ( isDefined( self.suicideprompt ) ) { self.suicideprompt settext( &"ZOMBIE_BUTTON_TO_SUICIDE" ); } return suicided; } can_suicide() //checked matches cerberus output { if ( !isalive( self ) ) { return 0; } if ( !self player_is_in_laststand() ) { return 0; } if ( !isDefined( self.suicideprompt ) ) { return 0; } if ( is_true( self.is_zombie ) ) { return 0; } if ( is_true( level.intermission ) ) { return 0; } return 1; } is_suiciding( revivee ) //checked changed at own discretion { if ( self usebuttonpressed() && can_suicide() ) { return 1; } return 0; } revive_trigger_spawn() //checked changed to match cerberus output { if ( isDefined( level.revive_trigger_spawn_override_link ) ) { [[ level.revive_trigger_spawn_override_link ]]( self ); } else { radius = getDvarInt( "revive_trigger_radius" ); self.revivetrigger = spawn( "trigger_radius", ( 0, 0, 0 ), 0, radius, radius ); self.revivetrigger sethintstring( "" ); self.revivetrigger setcursorhint( "HINT_NOICON" ); self.revivetrigger setmovingplatformenabled( 1 ); self.revivetrigger enablelinkto(); self.revivetrigger.origin = self.origin; self.revivetrigger linkto( self ); self.revivetrigger.beingrevived = 0; self.revivetrigger.createtime = getTime(); } self thread revive_trigger_think(); } revive_trigger_think() //checked partially changed to match cerberus output //did not change while loop to for loop because of infinite loop continue bug { self endon( "disconnect" ); self endon( "zombified" ); self endon( "stop_revive_trigger" ); level endon( "end_game" ); self endon( "death" ); while ( 1 ) { wait 0.1; self.revivetrigger sethintstring( "" ); players = get_players(); for ( i = 0; i < players.size; i++ ) { d = 0; d = self depthinwater(); if ( players[ i ] can_revive( self ) || d > 20 ) { self.revivetrigger setrevivehintstring( &"ZOMBIE_BUTTON_TO_REVIVE_PLAYER", self.team ); break; } } i = 0; while ( i < players.size ) { reviver = players[ i ]; if ( self == reviver || !reviver is_reviving( self ) ) { i++; continue; } gun = reviver getcurrentweapon(); /* /# assert( isDefined( gun ) ); #/ */ if ( gun == level.revive_tool ) { i++; continue; } reviver giveweapon( level.revive_tool ); reviver switchtoweapon( level.revive_tool ); reviver setweaponammostock( level.revive_tool, 1 ); revive_success = reviver revive_do_revive( self, gun ); reviver revive_give_back_weapons( gun ); if ( isplayer( self ) ) { self allowjump( 1 ); } self.laststand = undefined; if ( revive_success ) { if ( isplayer( self ) ) { maps/mp/zombies/_zm_chugabud::player_revived_cleanup_chugabud_corpse(); } self thread revive_success( reviver ); self cleanup_suicide_hud(); return; } i++; } } } revive_give_back_weapons( gun ) //checked matches cerberus output { self takeweapon( level.revive_tool ); if ( self player_is_in_laststand() ) { return; } if ( gun != "none" && !is_placeable_mine( gun ) && gun != "equip_gasmask_zm" && gun != "lower_equip_gasmask_zm" && self hasweapon( gun ) ) { self switchtoweapon( gun ); } else { primaryweapons = self getweaponslistprimaries(); if ( isDefined( primaryweapons ) && primaryweapons.size > 0 ) { self switchtoweapon( primaryweapons[ 0 ] ); } } } can_revive( revivee ) //checked changed to match cerberus output { if ( !isDefined( revivee.revivetrigger ) ) { return 0; } if ( !isalive( self ) ) { return 0; } if ( self player_is_in_laststand() ) { return 0; } if ( self.team != revivee.team ) { return 0; } if ( is_true( self.is_zombie ) ) { return 0; } if ( self has_powerup_weapon() ) { return 0; } if ( is_true( level.can_revive_use_depthinwater_test ) && revivee depthinwater() > 10 ) { return 1; } if ( isDefined( level.can_revive ) && ![[ level.can_revive ]]( revivee ) ) { return 0; } if ( isDefined( level.can_revive_game_module ) && ![[ level.can_revive_game_module ]]( revivee ) ) { return 0; } ignore_sight_checks = 0; ignore_touch_checks = 0; if ( isDefined( level.revive_trigger_should_ignore_sight_checks ) ) { ignore_sight_checks = [[ level.revive_trigger_should_ignore_sight_checks ]]( self ); if ( ignore_sight_checks && isDefined( revivee.revivetrigger.beingrevived ) && revivee.revivetrigger.beingrevived == 1 ) { ignore_touch_checks = 1; } } if ( !ignore_touch_checks ) { if ( !self istouching( revivee.revivetrigger ) ) { return 0; } } if ( !ignore_sight_checks ) { if ( !self is_facing( revivee ) ) { return 0; } if ( !sighttracepassed( self.origin + vectorScale( ( 0, 0, 1 ), 50 ), revivee.origin + vectorScale( ( 0, 0, 1 ), 30 ), 0, undefined ) ) { return 0; } if ( !bullettracepassed( self.origin + vectorScale( ( 0, 0, 1 ), 50 ), revivee.origin + vectorScale( ( 0, 0, 1 ), 30 ), 0, undefined ) ) { return 0; } } return 1; } is_reviving( revivee ) //checked changed at own discretion { if ( self usebuttonpressed() && can_revive( revivee ) ) { return 1; } return 0; } is_reviving_any() //checked changed at own discretion { if ( is_true( self.is_reviving_any ) ) { return 1; } return 0; } is_facing( facee ) //checked matches cerberus output { orientation = self getplayerangles(); forwardvec = anglesToForward( orientation ); forwardvec2d = ( forwardvec[ 0 ], forwardvec[ 1 ], 0 ); unitforwardvec2d = vectornormalize( forwardvec2d ); tofaceevec = facee.origin - self.origin; tofaceevec2d = ( tofaceevec[ 0 ], tofaceevec[ 1 ], 0 ); unittofaceevec2d = vectornormalize( tofaceevec2d ); dotproduct = vectordot( unitforwardvec2d, unittofaceevec2d ); return dotproduct > 0.9; } revive_do_revive( playerbeingrevived, revivergun ) //checked changed to match cerberus output { /* /# assert( self is_reviving( playerbeingrevived ) ); #/ */ revivetime = 3; if ( self hasperk( "specialty_quickrevive" ) ) { revivetime /= 2; } if ( self maps/mp/zombies/_zm_pers_upgrades_functions::pers_revive_active() ) { revivetime *= 0.5; } timer = 0; revived = 0; playerbeingrevived.revivetrigger.beingrevived = 1; playerbeingrevived.revive_hud settext( &"ZOMBIE_PLAYER_IS_REVIVING_YOU", self ); playerbeingrevived revive_hud_show_n_fade( 3 ); playerbeingrevived.revivetrigger sethintstring( "" ); if ( isplayer( playerbeingrevived ) ) { playerbeingrevived startrevive( self ); } if ( !isDefined( self.reviveprogressbar ) ) { self.reviveprogressbar = self createprimaryprogressbar(); } if ( !isDefined( self.revivetexthud ) ) { self.revivetexthud = newclienthudelem( self ); } self thread laststand_clean_up_on_disconnect( playerbeingrevived, revivergun ); if ( !isDefined( self.is_reviving_any ) ) { self.is_reviving_any = 0; } self.is_reviving_any++; self thread laststand_clean_up_reviving_any( playerbeingrevived ); self.reviveprogressbar updatebar( 0.01, 1 / revivetime ); self.revivetexthud.alignx = "center"; self.revivetexthud.aligny = "middle"; self.revivetexthud.horzalign = "center"; self.revivetexthud.vertalign = "bottom"; self.revivetexthud.y = -113; if ( self issplitscreen() ) { self.revivetexthud.y = -347; } self.revivetexthud.foreground = 1; self.revivetexthud.font = "default"; self.revivetexthud.fontscale = 1.8; self.revivetexthud.alpha = 1; self.revivetexthud.color = ( 1, 1, 1 ); self.revivetexthud.hidewheninmenu = 1; if ( self maps/mp/zombies/_zm_pers_upgrades_functions::pers_revive_active() ) { self.revivetexthud.color = ( 0.5, 0.5, 1 ); } self.revivetexthud settext( &"ZOMBIE_REVIVING" ); self thread check_for_failed_revive( playerbeingrevived ); while ( self is_reviving( playerbeingrevived ) ) { wait 0.05; timer += 0.05; if ( self player_is_in_laststand() ) { break; } else if ( isDefined( playerbeingrevived.revivetrigger.auto_revive ) && playerbeingrevived.revivetrigger.auto_revive == 1 ) { break; } if ( timer >= revivetime ) { revived = 1; break; } } if ( isDefined( self.reviveprogressbar ) ) { self.reviveprogressbar destroyelem(); } if ( isDefined( self.revivetexthud ) ) { self.revivetexthud destroy(); } if ( isDefined( playerbeingrevived.revivetrigger.auto_revive ) && playerbeingrevived.revivetrigger.auto_revive == 1 ) { } else if ( !revived ) { if ( isplayer( playerbeingrevived ) ) { playerbeingrevived stoprevive( self ); } } playerbeingrevived.revivetrigger sethintstring( &"ZOMBIE_BUTTON_TO_REVIVE_PLAYER" ); playerbeingrevived.revivetrigger.beingrevived = 0; self notify( "do_revive_ended_normally" ); self.is_reviving_any--; if ( !revived ) { playerbeingrevived thread checkforbleedout( self ); } return revived; } checkforbleedout( player ) //checked matches cerberus output { self endon( "player_revived" ); self endon( "player_suicide" ); self endon( "disconnect" ); player endon( "disconnect" ); if ( is_classic() ) { player.failed_revives++; player notify( "player_failed_revive" ); } } auto_revive( reviver, dont_enable_weapons ) //checked changed to match cerberus output { if ( isDefined( self.revivetrigger ) ) { self.revivetrigger.auto_revive = 1; while ( self.revivetrigger.beingrevived == 1 ) { while ( 1 ) { if ( self.revivetrigger.beingrevived == 0 ) { break; } wait_network_frame(); } } self.revivetrigger.auto_trigger = 0; } self reviveplayer(); self maps/mp/zombies/_zm_perks::perk_set_max_health_if_jugg( "health_reboot", 1, 0 ); setclientsysstate( "lsm", "0", self ); self notify( "stop_revive_trigger" ); if ( isDefined( self.revivetrigger ) ) { self.revivetrigger delete(); self.revivetrigger = undefined; } self cleanup_suicide_hud(); if ( !isDefined( dont_enable_weapons ) || dont_enable_weapons == 0 ) { self laststand_enable_player_weapons(); } self allowjump( 1 ); self.ignoreme = 0; self.laststand = undefined; if ( !is_true( level.isresetting_grief ) ) { reviver.revives++; reviver maps/mp/zombies/_zm_stats::increment_client_stat( "revives" ); reviver maps/mp/zombies/_zm_stats::increment_player_stat( "revives" ); self recordplayerrevivezombies( reviver ); maps/mp/_demo::bookmark( "zm_player_revived", getTime(), self, reviver ); } self notify( "player_revived" ); } remote_revive( reviver ) //checked matches cerberus output { if ( !self player_is_in_laststand() ) { return; } self auto_revive( reviver ); } revive_success( reviver, b_track_stats ) //checked changed to match cerberus output { if ( !isDefined( b_track_stats ) ) { b_track_stats = 1; } if ( !isplayer( self ) ) { self notify( "player_revived", reviver ); return; } if ( is_true( b_track_stats ) ) { maps/mp/_demo::bookmark( "zm_player_revived", getTime(), self, reviver ); } self notify( "player_revived", reviver ); self reviveplayer(); self maps/mp/zombies/_zm_perks::perk_set_max_health_if_jugg( "health_reboot", 1, 0 ); if ( is_true( self.pers_upgrades_awarded[ "perk_lose" ] ) ) { self thread maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_perk_lose_restore(); } if ( !is_true( level.isresetting_grief ) && is_true( b_track_stats ) ) { reviver.revives++; reviver maps/mp/zombies/_zm_stats::increment_client_stat( "revives" ); reviver maps/mp/zombies/_zm_stats::increment_player_stat( "revives" ); self recordplayerrevivezombies( reviver ); reviver.upgrade_fx_origin = self.origin; } if ( is_classic() && is_true( b_track_stats ) ) { maps/mp/zombies/_zm_pers_upgrades_functions::pers_increment_revive_stat( reviver ); } if ( is_true( b_track_stats ) ) { reviver thread check_for_sacrifice(); } setclientsysstate( "lsm", "0", self ); self.revivetrigger delete(); self.revivetrigger = undefined; self cleanup_suicide_hud(); self laststand_enable_player_weapons(); self.ignoreme = 0; } revive_force_revive( reviver ) //checked matches cerberus output { /* /# assert( isDefined( self ) ); #/ /# assert( isplayer( self ) ); #/ /# assert( self player_is_in_laststand() ); #/ */ self thread revive_success( reviver ); } revive_hud_create() //checked matches cerberus output { self.revive_hud = newclienthudelem( self ); self.revive_hud.alignx = "center"; self.revive_hud.aligny = "middle"; self.revive_hud.horzalign = "center"; self.revive_hud.vertalign = "bottom"; self.revive_hud.foreground = 1; self.revive_hud.font = "default"; self.revive_hud.fontscale = 1.5; self.revive_hud.alpha = 0; self.revive_hud.color = ( 1, 1, 1 ); self.revive_hud.hidewheninmenu = 1; self.revive_hud settext( "" ); self.revive_hud.y = -160; } revive_hud_think() //checked partially changed to match cerberus output //did not change while loops to for loops to prevent infinite loop bug due to continue { self endon( "disconnect" ); while ( 1 ) { wait 0.1; if ( !player_any_player_in_laststand() ) { continue; } players = get_players(); playertorevive = undefined; i = 0; while ( i < players.size ) { if ( !isDefined( players[ i ].revivetrigger ) || !isDefined( players[ i ].revivetrigger.createtime ) ) { i++; continue; } if ( !isDefined( playertorevive ) || playertorevive.revivetrigger.createtime > players[ i ].revivetrigger.createtime ) { playertorevive = players[ i ]; } i++; } if ( isDefined( playertorevive ) ) { i = 0; while ( i < players.size ) { if ( players[ i ] player_is_in_laststand() ) { i++; continue; } if ( getDvar( "g_gametype" ) == "vs" ) { if ( players[ i ].team != playertorevive.team ) { i++; continue; } } if ( is_encounter() ) { if ( players[ i ].sessionteam != playertorevive.sessionteam ) { i++; continue; } if ( is_true( level.hide_revive_message ) ) { i++; continue; } } players[ i ] thread faderevivemessageover( playertorevive, 3 ); i++; } playertorevive.revivetrigger.createtime = undefined; wait 3.5; } } } faderevivemessageover( playertorevive, time ) //checked matches cerberus output { revive_hud_show(); self.revive_hud settext( &"ZOMBIE_PLAYER_NEEDS_TO_BE_REVIVED", playertorevive ); self.revive_hud fadeovertime( time ); self.revive_hud.alpha = 0; } revive_hud_show() //checked matches cerberus output { /* /# assert( isDefined( self ) ); #/ /# assert( isDefined( self.revive_hud ) ); #/ */ self.revive_hud.alpha = 1; } revive_hud_show_n_fade( time ) //checked matches cerberus output { revive_hud_show(); self.revive_hud fadeovertime( time ); self.revive_hud.alpha = 0; } drawcylinder( pos, rad, height ) //checked matches cerberus output //may need to review order of operations { /* /# currad = rad; curheight = height; r = 0; while ( r < 20 ) { theta = ( r / 20 ) * 360; theta2 = ( ( r + 1 ) / 20 ) * 360; line( pos + ( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos + ( cos( theta2 ) * currad, sin( theta2 ) * currad, 0 ) ); line( pos + ( cos( theta ) * currad, sin( theta ) * currad, curheight ), pos + ( cos( theta2 ) * currad, sin( theta2 ) * currad, curheight ) ); line( pos + ( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos + ( cos( theta ) * currad, sin( theta ) * currad, curheight ) ); r++; #/ } */ } get_lives_remaining() //checked matches cerberus output { /* /# assert( level.laststandgetupallowed, "Lives only exist in the Laststand type GETUP." ); #/ */ if ( level.laststandgetupallowed && isDefined( self.laststand_info ) && isDefined( self.laststand_info.type_getup_lives ) ) { return max( 0, self.laststand_info.type_getup_lives ); } return 0; } update_lives_remaining( increment ) //checked changed to match cerberus output //probably causes a crash since ternary operators may not be supported by the current compiler { /* /# assert( level.laststandgetupallowed, "Lives only exist in the Laststand type GETUP." ); #/ /# assert( isDefined( increment ), "Must specify increment true or false" ); #/ */ increment = (isdefined( increment )?increment:false ); self.laststand_info.type_getup_lives = max( 0, ( increment?self.laststand_info.type_getup_lives + 1:self.laststand_info.type_getup_lives - 1 ) ); self notify( "laststand_lives_updated", self.laststand_info.type_getup_lives + 1, increment ); } player_getup_setup() //checked matches cerberus output { /* /# println( "ZM >> player_getup_setup called" ); #/ */ self.laststand_info = spawnstruct(); self.laststand_info.type_getup_lives = level.const_laststand_getup_count_start; } laststand_getup() //checked matches cerberus output { self endon( "player_revived" ); self endon( "disconnect" ); /* /# println( "ZM >> laststand_getup called" ); #/ */ self update_lives_remaining( 0 ); setclientsysstate( "lsm", "1", self ); self.laststand_info.getup_bar_value = level.const_laststand_getup_bar_start; self thread laststand_getup_hud(); self thread laststand_getup_damage_watcher(); while ( self.laststand_info.getup_bar_value < 1 ) { self.laststand_info.getup_bar_value += level.const_laststand_getup_bar_regen; wait 0.05; } self auto_revive( self ); setclientsysstate( "lsm", "0", self ); } laststand_getup_damage_watcher() //checked matches cerberus output { self endon( "player_revived" ); self endon( "disconnect" ); while ( 1 ) { self waittill( "damage" ); self.laststand_info.getup_bar_value -= level.const_laststand_getup_bar_damage; if ( self.laststand_info.getup_bar_value < 0 ) { self.laststand_info.getup_bar_value = 0; } } } laststand_getup_hud() //checked matches cerberus output { self endon( "player_revived" ); self endon( "disconnect" ); hudelem = newclienthudelem( self ); hudelem.alignx = "left"; hudelem.aligny = "middle"; hudelem.horzalign = "left"; hudelem.vertalign = "middle"; hudelem.x = 5; hudelem.y = 170; hudelem.font = "big"; hudelem.fontscale = 1.5; hudelem.foreground = 1; hudelem.hidewheninmenu = 1; hudelem.hidewhendead = 1; hudelem.sort = 2; hudelem.label = &"SO_WAR_LASTSTAND_GETUP_BAR"; self thread laststand_getup_hud_destroy( hudelem ); while ( 1 ) { hudelem setvalue( self.laststand_info.getup_bar_value ); wait 0.05; } } laststand_getup_hud_destroy( hudelem ) //checked matches cerberus output { self waittill_either( "player_revived", "disconnect" ); hudelem destroy(); } check_for_sacrifice() //checked matches cerberus output { self delay_notify( "sacrifice_denied", 1 ); self endon( "sacrifice_denied" ); self waittill( "player_downed" ); self maps/mp/zombies/_zm_stats::increment_client_stat( "sacrifices" ); self maps/mp/zombies/_zm_stats::increment_player_stat( "sacrifices" ); } check_for_failed_revive( playerbeingrevived ) //checked matches cerberus output { self endon( "disconnect" ); playerbeingrevived endon( "disconnect" ); playerbeingrevived endon( "player_suicide" ); self notify( "checking_for_failed_revive" ); self endon( "checking_for_failed_revive" ); playerbeingrevived endon( "player_revived" ); playerbeingrevived waittill( "bled_out" ); self maps/mp/zombies/_zm_stats::increment_client_stat( "failed_revives" ); self maps/mp/zombies/_zm_stats::increment_player_stat( "failed_revives" ); } add_weighted_down() //checked matches cerberus output { if ( !level.curr_gametype_affects_rank ) { return; } weighted_down = 1000; if ( level.round_number > 0 ) { weighted_down = int( 1000 / ceil( level.round_number / 5 ) ); } self addplayerstat( "weighted_downs", weighted_down ); } cleanup_laststand_on_disconnect() //checked matches cerberus output { self endon( "player_revived" ); self endon( "player_suicide" ); self endon( "bled_out" ); trig = self.revivetrigger; self waittill( "disconnect" ); if ( isDefined( trig ) ) { trig delete(); } }