7317 lines
204 KiB
Plaintext
7317 lines
204 KiB
Plaintext
#using scripts\codescripts\struct;
|
|
|
|
#using scripts\shared\aat_shared;
|
|
#using scripts\shared\ai_puppeteer_shared;
|
|
#using scripts\shared\archetype_shared\archetype_shared;
|
|
#using scripts\shared\array_shared;
|
|
#using scripts\shared\callbacks_shared;
|
|
#using scripts\shared\clientfield_shared;
|
|
#using scripts\shared\demo_shared;
|
|
#using scripts\shared\flag_shared;
|
|
#using scripts\shared\hud_util_shared;
|
|
#using scripts\shared\laststand_shared;
|
|
#using scripts\shared\lui_shared;
|
|
#using scripts\shared\math_shared;
|
|
#using scripts\shared\scoreevents_shared;
|
|
#using scripts\shared\system_shared;
|
|
#using scripts\shared\util_shared;
|
|
#using scripts\shared\visionset_mgr_shared;
|
|
#using scripts\zm\gametypes\_globallogic;
|
|
#using scripts\zm\gametypes\_globallogic_vehicle;
|
|
|
|
#using scripts\zm\_bb;
|
|
|
|
#using scripts\shared\ai\systems\gib;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#using scripts\zm\gametypes\_weapons;
|
|
#using scripts\zm\gametypes\_zm_gametype;
|
|
#using scripts\zm\gametypes\_globallogic_spawn;
|
|
#using scripts\zm\gametypes\_globallogic_player;
|
|
|
|
#using scripts\zm\_util;
|
|
#using scripts\zm\_zm_attackables;
|
|
#using scripts\zm\_zm_audio;
|
|
#using scripts\zm\_zm_bgb;
|
|
#using scripts\zm\_zm_bgb_token;
|
|
#using scripts\zm\_zm_blockers;
|
|
#using scripts\zm\_zm_bot;
|
|
#using scripts\zm\_zm_daily_challenges;
|
|
#using scripts\zm\_zm_equipment;
|
|
#using scripts\zm\_zm_ffotd;
|
|
#using scripts\zm\_zm_game_module;
|
|
//#using scripts\zm\_zm_hero_weapon;
|
|
#using scripts\zm\_zm_laststand;
|
|
#using scripts\zm\_zm_melee_weapon;
|
|
#using scripts\zm\_zm_perks;
|
|
#using scripts\zm\_zm_pers_upgrades;
|
|
#using scripts\zm\_zm_pers_upgrades_functions;
|
|
#using scripts\zm\_zm_pers_upgrades_system;
|
|
#using scripts\zm\_zm_placeable_mine;
|
|
#using scripts\zm\_zm_player;
|
|
#using scripts\zm\_zm_powerups;
|
|
#using scripts\zm\_zm_score;
|
|
#using scripts\zm\_zm_spawner;
|
|
#using scripts\zm\_zm_stats;
|
|
#using scripts\zm\_zm_timer;
|
|
#using scripts\zm\_zm_unitrigger;
|
|
#using scripts\zm\_zm_utility;
|
|
#using scripts\zm\_zm_weapons;
|
|
#using scripts\zm\_zm_zonemgr;
|
|
#using scripts\shared\ai_shared;
|
|
|
|
// AATs
|
|
|
|
#using scripts\zm\aats\_zm_aat_blast_furnace;
|
|
#using scripts\zm\aats\_zm_aat_dead_wire;
|
|
#using scripts\zm\aats\_zm_aat_fire_works;
|
|
#using scripts\zm\aats\_zm_aat_thunder_wall;
|
|
#using scripts\zm\aats\_zm_aat_turned;
|
|
|
|
// BGBs
|
|
#using scripts\zm\bgbs\_zm_bgb_aftertaste;
|
|
#using scripts\zm\bgbs\_zm_bgb_alchemical_antithesis;
|
|
#using scripts\zm\bgbs\_zm_bgb_always_done_swiftly;
|
|
#using scripts\zm\bgbs\_zm_bgb_anywhere_but_here;
|
|
#using scripts\zm\bgbs\_zm_bgb_armamental_accomplishment;
|
|
#using scripts\zm\bgbs\_zm_bgb_arms_grace;
|
|
#using scripts\zm\bgbs\_zm_bgb_arsenal_accelerator;
|
|
#using scripts\zm\bgbs\_zm_bgb_burned_out;
|
|
#using scripts\zm\bgbs\_zm_bgb_cache_back;
|
|
#using scripts\zm\bgbs\_zm_bgb_coagulant;
|
|
#using scripts\zm\bgbs\_zm_bgb_danger_closest;
|
|
#using scripts\zm\bgbs\_zm_bgb_dead_of_nuclear_winter;
|
|
#using scripts\zm\bgbs\_zm_bgb_ephemeral_enhancement;
|
|
#using scripts\zm\bgbs\_zm_bgb_firing_on_all_cylinders;
|
|
#using scripts\zm\bgbs\_zm_bgb_im_feelin_lucky;
|
|
#using scripts\zm\bgbs\_zm_bgb_immolation_liquidation;
|
|
#using scripts\zm\bgbs\_zm_bgb_impatient;
|
|
#using scripts\zm\bgbs\_zm_bgb_in_plain_sight;
|
|
#using scripts\zm\bgbs\_zm_bgb_kill_joy;
|
|
#using scripts\zm\bgbs\_zm_bgb_killing_time;
|
|
#using scripts\zm\bgbs\_zm_bgb_licensed_contractor;
|
|
#using scripts\zm\bgbs\_zm_bgb_lucky_crit;
|
|
#using scripts\zm\bgbs\_zm_bgb_now_you_see_me;
|
|
#using scripts\zm\bgbs\_zm_bgb_on_the_house;
|
|
#using scripts\zm\bgbs\_zm_bgb_perkaholic;
|
|
#using scripts\zm\bgbs\_zm_bgb_phoenix_up;
|
|
#using scripts\zm\bgbs\_zm_bgb_pop_shocks;
|
|
#using scripts\zm\bgbs\_zm_bgb_respin_cycle;
|
|
#using scripts\zm\bgbs\_zm_bgb_stock_option;
|
|
#using scripts\zm\bgbs\_zm_bgb_sword_flay;
|
|
#using scripts\zm\bgbs\_zm_bgb_unquenchable;
|
|
#using scripts\zm\bgbs\_zm_bgb_wall_power;
|
|
#using scripts\zm\bgbs\_zm_bgb_whos_keeping_score;
|
|
|
|
// DLC1 BGBS
|
|
#using scripts\zm\bgbs\_zm_bgb_crawl_space;
|
|
#using scripts\zm\bgbs\_zm_bgb_fatal_contraption;
|
|
#using scripts\zm\bgbs\_zm_bgb_head_drama;
|
|
#using scripts\zm\bgbs\_zm_bgb_undead_man_walking;
|
|
|
|
// DLC2 BGBS
|
|
#using scripts\zm\bgbs\_zm_bgb_fear_in_headlights;
|
|
#using scripts\zm\bgbs\_zm_bgb_secret_shopper;
|
|
#using scripts\zm\bgbs\_zm_bgb_temporal_gift;
|
|
#using scripts\zm\bgbs\_zm_bgb_unbearable;
|
|
|
|
// DLC3 BGBS
|
|
#using scripts\zm\bgbs\_zm_bgb_crate_power;
|
|
#using scripts\zm\bgbs\_zm_bgb_disorderly_combat;
|
|
#using scripts\zm\bgbs\_zm_bgb_projectile_vomiting;
|
|
#using scripts\zm\bgbs\_zm_bgb_shopping_free;
|
|
#using scripts\zm\bgbs\_zm_bgb_slaughter_slide;
|
|
|
|
// DLC4 BGBS
|
|
#using scripts\zm\bgbs\_zm_bgb_bullet_boost;
|
|
#using scripts\zm\bgbs\_zm_bgb_mind_blown;
|
|
#using scripts\zm\bgbs\_zm_bgb_near_death_experience;
|
|
#using scripts\zm\bgbs\_zm_bgb_newtonian_negation;
|
|
#using scripts\zm\bgbs\_zm_bgb_profit_sharing;
|
|
#using scripts\zm\bgbs\_zm_bgb_round_robbin;
|
|
#using scripts\zm\bgbs\_zm_bgb_self_medication;
|
|
|
|
// DLC5 BGBS
|
|
#using scripts\zm\bgbs\_zm_bgb_board_games;
|
|
#using scripts\zm\bgbs\_zm_bgb_board_to_death;
|
|
#using scripts\zm\bgbs\_zm_bgb_extra_credit;
|
|
#using scripts\zm\bgbs\_zm_bgb_eye_candy;
|
|
#using scripts\zm\bgbs\_zm_bgb_flavor_hexed;
|
|
#using scripts\zm\bgbs\_zm_bgb_idle_eyes;
|
|
#using scripts\zm\bgbs\_zm_bgb_power_vacuum;
|
|
#using scripts\zm\bgbs\_zm_bgb_reign_drops;
|
|
#using scripts\zm\bgbs\_zm_bgb_soda_fountain;
|
|
#using scripts\zm\bgbs\_zm_bgb_tone_death;
|
|
|
|
// DLC5 BGB REQUIRED POWERUPS
|
|
#using scripts\zm\_zm_powerup_bonus_points_player;
|
|
|
|
#using scripts\zm\craftables\_zm_craftables;
|
|
|
|
#using scripts\shared\ai\zombie_death;
|
|
#using scripts\shared\ai\zombie_utility;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#precache( "material", "hud_chalk_1" );
|
|
#precache( "material", "hud_chalk_2" );
|
|
#precache( "material", "hud_chalk_3" );
|
|
#precache( "material", "hud_chalk_4" );
|
|
#precache( "material", "hud_chalk_5" );
|
|
|
|
#precache( "material", "zom_icon_community_pot" );
|
|
#precache( "material", "zom_icon_community_pot_strip" );
|
|
|
|
#precache( "material","zom_icon_player_life");
|
|
|
|
#precache( "string", "ZOMBIE_WEAPONCOSTAMMO" );
|
|
#precache( "string", "ZOMBIE_ROUND" );
|
|
#precache( "string", "SCRIPT_PLUS" );
|
|
#precache( "string", "ZOMBIE_GAME_OVER" );
|
|
#precache( "string", "ZOMBIE_SURVIVED_ROUND" );
|
|
#precache( "string", "ZOMBIE_SURVIVED_ROUNDS" );
|
|
#precache( "string", "ZOMBIE_SURVIVED_NOMANS" );
|
|
#precache( "string", "ZOMBIE_EXTRA_LIFE" );
|
|
#precache( "string", "ZOMBIE_UNDEFINED" );
|
|
#precache( "triggerstring", "ZOMBIE_ELECTRIC_SWITCH" );
|
|
#precache( "triggerstring", "ZOMBIE_NEED_POWER" );
|
|
// Random Treasure Chest
|
|
#precache( "string", "ZOMBIE_RANDOM_WEAPON_COST" );
|
|
// Weapons
|
|
#precache( "string", "ZOMBIE_WEAPON_COSTONLYFILL_500" );
|
|
#precache( "triggerstring", "ZOMBIE_WEAPON_COSTONLYFILL_2000" );
|
|
#precache( "triggerstring", "ZOMBIE_WEAPONAMMOONLY_250" );
|
|
#precache( "triggerstring", "ZOMBIE_WEAPONCOSTAMMO_UPGRADE_500_250" );
|
|
// Barrier Pieces
|
|
#precache( "string", "ZOMBIE_BUTTON_BUY_BACK_BARRIER_10" );
|
|
#precache( "string", "ZOMBIE_BUTTON_BUY_BACK_BARRIER_20" );
|
|
#precache( "string", "ZOMBIE_BUTTON_BUY_BACK_BARRIER_50" );
|
|
#precache( "string", "ZOMBIE_BUTTON_BUY_BACK_BARRIER_100" );
|
|
// REWARD Barrier Pieces
|
|
#precache( "string", "ZOMBIE_BUTTON_REWARD_BARRIER" );
|
|
// Debris
|
|
#precache( "string", "ZOMBIE_BUTTON_BUY_CLEAR_DEBRIS_COST" );
|
|
// Doors
|
|
#precache( "string", "ZOMBIE_BUTTON_BUY_OPEN_DOOR_COST" );
|
|
#precache( "string", "ZOMBIE_BUTTON_BUY_CLOSE_DOOR" );
|
|
|
|
#precache( "triggerstring", "ZOMBIE_BUTTON_REWARD_BARRIER" );
|
|
|
|
#precache( "fx", "_t6/maps/zombie/fx_zombie_bar_break" );
|
|
#precache( "fx", "_t6/maps/zombie/fx_zombie_bar_break_lite" );
|
|
#precache( "fx", "_t6/maps/zombie/fx_fog_zombie_amb" );
|
|
#precache( "fx", "zombie/fx_weapon_box_open_glow_zmb" );
|
|
#precache( "fx", "zombie/fx_weapon_box_closed_glow_zmb" );
|
|
#precache( "fx", "zombie/fx_glow_eye_orange" );
|
|
#precache( "fx", "zombie/fx_bul_flesh_head_fatal_zmb" );
|
|
#precache( "fx", "zombie/fx_bul_flesh_head_nochunks_zmb" );
|
|
#precache( "fx", "zombie/fx_bul_flesh_neck_spurt_zmb" );
|
|
#precache( "fx", "_t6/maps/zombie/fx_zombie_tesla_neck_spurt" );
|
|
#precache( "fx", "zombie/fx_blood_torso_explo_zmb" );
|
|
#precache( "fx", "zombie/fx_blood_torso_explo_lg_zmb" );
|
|
#precache( "fx", "zombie/fx_spawn_dirt_hand_burst_zmb" );
|
|
#precache( "fx", "zombie/fx_spawn_dirt_body_billowing_zmb" );
|
|
#precache( "fx", "zombie/fx_spawn_dirt_body_dustfalling_zmb" );
|
|
#precache( "fx", "zombie/fx_fire_torso_zmb" );
|
|
#precache( "fx", "_t6/explosions/fx_default_explosion" );
|
|
#precache( "fx", "_t6/maps/zombie/fx_zmb_tanzit_upgrade" );
|
|
|
|
#precache( "menu", "StartMenu_Main" );
|
|
#precache( "menu", "InitialBlack" );
|
|
|
|
#precache( "eventstring", "force_scoreboard" );
|
|
#precache( "eventstring", "open_ingame_menu" );
|
|
#precache( "eventstring", "play_promo_anim" );
|
|
|
|
#precache( "string", "ZOMBIE_REVIVING_SOLO", "ZOMBIE_PLAYER_NAME_0" );
|
|
#precache( "string", "ZOMBIE_REVIVING_SOLO", "ZOMBIE_PLAYER_NAME_1" );
|
|
#precache( "string", "ZOMBIE_REVIVING_SOLO", "ZOMBIE_PLAYER_NAME_2" );
|
|
#precache( "string", "ZOMBIE_REVIVING_SOLO", "ZOMBIE_PLAYER_NAME_3" );
|
|
|
|
#namespace zm;
|
|
|
|
function autoexec ignore_systems()
|
|
{
|
|
//shutdown unwanted systems - doing it in an autoexec is the only clean way to do it
|
|
system::ignore("gadget_clone");
|
|
system::ignore("gadget_armor");
|
|
system::ignore("gadget_heat_wave");
|
|
system::ignore("gadget_resurrect");
|
|
system::ignore("gadget_shock_field");
|
|
system::ignore("gadget_active_camo");
|
|
system::ignore("gadget_mrpukey");
|
|
system::ignore("gadget_misdirection");
|
|
system::ignore("gadget_smokescreen");
|
|
system::ignore("gadget_firefly_swarm");
|
|
system::ignore("gadget_immolation");
|
|
system::ignore("gadget_forced_malfunction");
|
|
system::ignore("gadget_sensory_overload");
|
|
system::ignore("gadget_rapid_strike");
|
|
system::ignore("gadget_unstoppable_force");
|
|
system::ignore("gadget_overdrive");
|
|
system::ignore("gadget_concussive_wave");
|
|
system::ignore("gadget_ravage_core");
|
|
system::ignore("gadget_es_strike");
|
|
system::ignore("gadget_cacophany");
|
|
system::ignore("gadget_iff_override");
|
|
system::ignore("gadget_security_breach");
|
|
system::ignore("gadget_surge");
|
|
system::ignore("gadget_exo_breakdown");
|
|
system::ignore("gadget_servo_shortout");
|
|
system::ignore("gadget_system_overload");
|
|
system::ignore("gadget_cleanse");
|
|
system::ignore("gadget_flashback");
|
|
system::ignore("gadget_combat_efficiency");
|
|
system::ignore("gadget_other");
|
|
system::ignore("gadget_camo");
|
|
system::ignore("gadget_vision_pulse");
|
|
system::ignore("gadget_speed_burst");
|
|
system::ignore("gadget_thief");
|
|
system::ignore("replay_gun");
|
|
system::ignore("spike_charge_siegebot");
|
|
system::ignore("siegebot");
|
|
system::ignore("amws");
|
|
|
|
}
|
|
|
|
|
|
|
|
function autoexec __init__sytem__() { system::register("zm",&__init__,undefined,undefined); }
|
|
|
|
function __init__()
|
|
{
|
|
if(!isdefined(level.zombie_vars))level.zombie_vars=[];
|
|
}
|
|
|
|
function init()
|
|
{
|
|
//New movement disabled for Zombies
|
|
SetDvar( "doublejump_enabled", 0 );
|
|
SetDvar( "juke_enabled", 0 );
|
|
SetDvar( "playerEnergy_enabled", 0 );
|
|
SetDvar( "wallrun_enabled", 0 );
|
|
SetDvar( "sprintLeap_enabled", 0 );
|
|
SetDvar( "traverse_mode", 2 );
|
|
SetDvar( "weaponrest_enabled", 0 );
|
|
|
|
//we dont care about CP movie skipping logic in ZM
|
|
SetDvar( "ui_allowDisplayContinue", true );
|
|
|
|
if ( !IsDefined( level.killstreakWeapons ) )
|
|
{
|
|
level.killstreakWeapons = [];
|
|
}
|
|
|
|
level.weaponNone = GetWeapon( "none" );
|
|
level.weaponNull = GetWeapon( "weapon_null" );
|
|
level.weaponBaseMelee = GetWeapon( "knife" );
|
|
level.weaponBaseMeleeHeld = GetWeapon( "knife_held" );
|
|
level.weaponBallisticKnife = GetWeapon( "knife_ballistic" );
|
|
if(!isdefined(level.weaponRiotshield))level.weaponRiotshield=GetWeapon( "riotshield" );
|
|
level.weaponReviveTool = GetWeapon( "syrette" );
|
|
level.weaponZMDeathThroe = GetWeapon( "death_throe" );
|
|
level.weaponZMFists = GetWeapon( "zombie_fists" );
|
|
|
|
if(!isdefined(level.giveCustomLoadout))level.giveCustomLoadout=&zm_weapons::give_start_weapons;
|
|
|
|
level.projectiles_should_ignore_world_pause = true;
|
|
|
|
level.player_out_of_playable_area_monitor = true;
|
|
level.player_too_many_weapons_monitor = true;
|
|
level.player_too_many_weapons_monitor_func = &player_too_many_weapons_monitor;
|
|
|
|
level.player_too_many_players_check = true;
|
|
level.player_too_many_players_check_func = &player_too_many_players_check;
|
|
|
|
level._use_choke_weapon_hints = 1;
|
|
level._use_choke_blockers = 1;
|
|
|
|
level.speed_change_round = 15;
|
|
|
|
level.passed_introscreen = false;
|
|
|
|
if(!isdefined(level.custom_ai_type))
|
|
{
|
|
level.custom_ai_type = [];
|
|
}
|
|
|
|
level.custom_ai_spawn_check_funcs = [];
|
|
|
|
// put things you'd like to be able to turn off in here above this line
|
|
level thread zm_ffotd::main_start();
|
|
|
|
level.zombiemode = true;
|
|
level.reviveFeature = false;
|
|
level.swimmingFeature = false;
|
|
level.calc_closest_player_using_paths = false;
|
|
level.zombie_melee_in_water = true;
|
|
level.put_timed_out_zombies_back_in_queue = true;
|
|
level.use_alternate_poi_positioning = true;
|
|
level.zmb_laugh_alias = "zmb_laugh_child";
|
|
level.sndAnnouncerIsRich = true;
|
|
|
|
level.scr_zm_ui_gametype = GetDvarString( "ui_gametype" );
|
|
level.scr_zm_ui_gametype_group = "";//GetDvarString( "ui_zm_gamemodegroup" );
|
|
level.scr_zm_map_start_location = "";//GetDvarString( "ui_zm_mapstartlocation" );
|
|
|
|
level.curr_gametype_affects_rank = false;
|
|
gametype = toLower( GetDvarString( "g_gametype" ) );
|
|
if ( "zclassic" == gametype || "zstandard" == gametype )
|
|
{
|
|
level.curr_gametype_affects_rank = true;
|
|
}
|
|
|
|
level.grenade_multiattack_bookmark_count = 1;
|
|
demo::initActorBookmarkParams( 3, 6000, 6000 );
|
|
|
|
// set up any gameplay modes
|
|
/* level.GAME_MODULE_CLASSIC_INDEX = 0;
|
|
zm_game_module::register_game_module(level.GAME_MODULE_CLASSIC_INDEX,"classic",undefined,undefined);
|
|
zm_game_module::set_current_game_module(level.scr_zm_game_module); */
|
|
|
|
// Allowing custom round_spawn_failsafe function to be set here.
|
|
if( !isdefined( level._zombies_round_spawn_failsafe ) )
|
|
{
|
|
level._zombies_round_spawn_failsafe = &zombie_utility::round_spawn_failsafe;
|
|
}
|
|
|
|
level.func_get_zombie_spawn_delay = &get_zombie_spawn_delay;
|
|
level.func_get_delay_between_rounds = &get_delay_between_rounds;
|
|
|
|
level.zombie_visionset = "zombie_neutral";
|
|
|
|
level.wait_and_revive = false;
|
|
|
|
if(GetDvarString("anim_intro") == "1")
|
|
{
|
|
level.zombie_anim_intro = 1;
|
|
}
|
|
else
|
|
{
|
|
level.zombie_anim_intro = 0;
|
|
}
|
|
|
|
precache_models();
|
|
|
|
precache_zombie_leaderboards();
|
|
|
|
level._ZOMBIE_GIB_PIECE_INDEX_ALL = 0;
|
|
level._ZOMBIE_GIB_PIECE_INDEX_RIGHT_ARM = 1;
|
|
level._ZOMBIE_GIB_PIECE_INDEX_LEFT_ARM = 2;
|
|
level._ZOMBIE_GIB_PIECE_INDEX_RIGHT_LEG = 3;
|
|
level._ZOMBIE_GIB_PIECE_INDEX_LEFT_LEG = 4;
|
|
level._ZOMBIE_GIB_PIECE_INDEX_HEAD = 5;
|
|
level._ZOMBIE_GIB_PIECE_INDEX_GUTS = 6;
|
|
level._ZOMBIE_GIB_PIECE_INDEX_HAT = 7;
|
|
|
|
//Limit zombie to 24 max, must have for network purposes
|
|
if ( !isdefined( level.zombie_ai_limit ) )
|
|
{
|
|
level.zombie_ai_limit = 24;
|
|
}
|
|
if ( !isdefined( level.zombie_actor_limit ) )
|
|
{
|
|
level.zombie_actor_limit = 31;
|
|
}
|
|
|
|
init_flags();
|
|
init_dvars();
|
|
init_strings();
|
|
init_levelvars();
|
|
init_sounds();
|
|
init_shellshocks();
|
|
init_client_field_callback_funcs();
|
|
|
|
zm_utility::register_offhand_weapons_for_level_defaults();
|
|
|
|
level thread drive_client_connected_notifies();
|
|
|
|
// load map defaults
|
|
|
|
//Systems
|
|
zm_craftables::init();
|
|
zm_perks::init();
|
|
zm_powerups::init();
|
|
zm_spawner::init();
|
|
zm_weapons::init();
|
|
|
|
//Grab all static poi in the map
|
|
level.zombie_poi_array = getEntArray( "zombie_poi", "script_noteworthy" );
|
|
|
|
|
|
init_function_overrides();
|
|
|
|
// ww: init the pistols in the game so last stand has the importance order
|
|
level thread last_stand_pistol_rank_init();
|
|
|
|
level thread post_all_players_connected();
|
|
|
|
level start_zm_dash_counter_watchers();
|
|
|
|
zm_utility::init_utility();
|
|
|
|
util::registerClientSys( "lsm" );
|
|
|
|
// STATS_TODO: will check if the following is needed later
|
|
initializeStatTracking();
|
|
|
|
if ( GetPlayers().size <= 1 )
|
|
{
|
|
incrementCounter( "global_solo_games", 1 );
|
|
}
|
|
else if( ( isdefined( level.systemLink ) && level.systemLink ) )
|
|
{
|
|
incrementCounter( "global_systemlink_games", 1 );
|
|
}
|
|
else if ( GetDvarInt( "splitscreen_playerCount" ) == GetPlayers().size )
|
|
{
|
|
incrementCounter( "global_splitscreen_games", 1 );
|
|
}
|
|
else // coop game
|
|
{
|
|
incrementCounter( "global_coop_games", 1 );
|
|
}
|
|
|
|
callback::on_connect( &zm_on_player_connect);
|
|
|
|
//self LUINotifyEvent( &"score_event", 3, label, score, rampageBonus );
|
|
|
|
// Initialize persistent upgrades
|
|
//zm_pers_upgrades::pers_upgrade_init();
|
|
|
|
zm_utility::set_demo_intermission_point();
|
|
|
|
level thread zm_ffotd::main_end();
|
|
level thread zm_utility::track_players_intersection_tracker();
|
|
level thread onAllPlayersReady();
|
|
level thread startUnitriggers();
|
|
|
|
level thread confuse_third_party_trainers();
|
|
|
|
callback::on_spawned( &zm_on_player_spawned );
|
|
printHashIDs();
|
|
}
|
|
|
|
function post_main()
|
|
{
|
|
level thread init_custom_ai_type();
|
|
}
|
|
|
|
function cheat_enabled( val )
|
|
{
|
|
if ( GetDvarInt( "zombie_cheat" ) >= val )
|
|
{
|
|
/#
|
|
return true;
|
|
#/
|
|
|
|
if ( IsProfileBuild() )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function confuse_third_party_trainers()
|
|
{
|
|
level flag::wait_till_any( array( "start_zombie_round_logic", "start_encounters_match_logic" ) );
|
|
while(1)
|
|
{
|
|
temp_var = get_round_number();
|
|
level.round_number = undefined;
|
|
temp_var2 = temp_var;
|
|
switch( RandomInt(5) )
|
|
{
|
|
case 0:
|
|
temp_var3 = temp_var;
|
|
case 1:
|
|
temp_var4 = temp_var;
|
|
case 2:
|
|
temp_var5 = temp_var;
|
|
case 3:
|
|
temp_var6 = temp_var;
|
|
case 4:
|
|
temp_var7 = temp_var;
|
|
}
|
|
level.round_number = temp_var;
|
|
temp_var = undefined;
|
|
temp_var1 = undefined;
|
|
temp_var2 = undefined;
|
|
temp_var3 = undefined;
|
|
temp_var4 = undefined;
|
|
temp_var5 = undefined;
|
|
temp_var6 = undefined;
|
|
temp_var7 = undefined;
|
|
|
|
|
|
{wait(.05);};
|
|
}
|
|
}
|
|
|
|
function set_round_number( new_round )
|
|
{
|
|
if ( new_round > 255 )
|
|
new_round = 255;
|
|
world.roundnumber = new_round ^ 115;
|
|
}
|
|
|
|
function get_round_number()
|
|
{
|
|
return world.roundnumber ^ 115;
|
|
}
|
|
|
|
|
|
function startUnitriggers()
|
|
{
|
|
level flag::wait_till_any( array( "start_zombie_round_logic", "start_encounters_match_logic" ) );
|
|
level thread zm_unitrigger::main();
|
|
}
|
|
|
|
function drive_client_connected_notifies()
|
|
{
|
|
while(1)
|
|
{
|
|
level waittill("connected", player);
|
|
player demo::reset_actor_bookmark_kill_times();
|
|
player callback::callback( #"on_player_connect" );
|
|
}
|
|
}
|
|
|
|
function fade_out_intro_screen_zm( hold_black_time, fade_out_time, destroyed_afterwards )
|
|
{
|
|
lui::screen_fade_out( 0, undefined );
|
|
|
|
if( IsDefined( hold_black_time ) )
|
|
{
|
|
wait hold_black_time;
|
|
}
|
|
else
|
|
{
|
|
wait 0.2;
|
|
}
|
|
|
|
if( !IsDefined( fade_out_time ) )
|
|
{
|
|
fade_out_time = 1.5;
|
|
}
|
|
|
|
array::thread_all(GetPlayers(), &initialBlackEnd);
|
|
level clientfield::set( "sndZMBFadeIn", 1 );
|
|
lui::screen_fade_in( fade_out_time, undefined );
|
|
|
|
//level notify("fade_introblack");
|
|
|
|
wait 1.6;
|
|
|
|
level.passed_introscreen = true;
|
|
|
|
players = GetPlayers();
|
|
for(i = 0; i < players.size; i++)
|
|
{
|
|
if( IsDefined( level.customHudReveal ) )
|
|
{
|
|
players[i] thread [[level.customHudReveal]]();
|
|
}
|
|
else
|
|
{
|
|
players[i] ShowHudAndPlayPromo();
|
|
}
|
|
|
|
if(!( isdefined( level.host_ended_game ) && level.host_ended_game ))
|
|
{
|
|
if (isdefined(level.player_movement_suppressed))
|
|
{
|
|
players[i] FreezeControls(level.player_movement_suppressed);
|
|
/# println(" Unfreeze controls 4"); #/
|
|
|
|
}
|
|
else
|
|
{
|
|
if(!( isdefined( players[i].hostMigrationControlsFrozen ) && players[i].hostMigrationControlsFrozen ))
|
|
{
|
|
players[i] FreezeControls(false);
|
|
|
|
/# println(" Unfreeze controls 5"); #/
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// level notify("fade_in_complete");
|
|
|
|
level flag::set("initial_blackscreen_passed");
|
|
level clientfield::set("gameplay_started", 1);
|
|
}
|
|
|
|
function ShowHudAndPlayPromo()
|
|
{
|
|
self setClientUIVisibilityFlag( "hud_visible", 1 );
|
|
self setClientUIVisibilityFlag( "weapon_hud_visible", 1 );
|
|
|
|
if( !( isdefined( self.seen_promo_anim ) && self.seen_promo_anim ) && SessionModeIsOnlineGame() )
|
|
{
|
|
self LUINotifyEvent( &"play_promo_anim", 0 );
|
|
self.seen_promo_anim = true;
|
|
}
|
|
}
|
|
|
|
function onAllPlayersReady()
|
|
{
|
|
|
|
timeOut = GetTime() + 5000; // 5 second time out.
|
|
|
|
while(IsLoadingCinematicPlaying() || (GetNumExpectedPlayers() == 0 && (GetTime() < timeOut)))
|
|
{
|
|
wait(0.1);
|
|
}
|
|
|
|
/# println( "ZM >> player_count_expected=" + GetNumExpectedPlayers()); #/
|
|
player_count_actual = 0;
|
|
while( (GetNumConnectedPlayers() < GetNumExpectedPlayers()) || (player_count_actual != GetNumExpectedPlayers()) )
|
|
{
|
|
players = GetPlayers();
|
|
player_count_actual = 0;
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
players[i] FreezeControls( true );
|
|
if( players[i].sessionstate == "playing" )
|
|
{
|
|
player_count_actual++;
|
|
}
|
|
}
|
|
|
|
/# println( "ZM >> Num Connected =" + GetNumConnectedPlayers() + " Expected : " + GetNumExpectedPlayers()); #/
|
|
wait( 0.1 );
|
|
}
|
|
|
|
SetInitialPlayersConnected();
|
|
|
|
level flag::set( "all_players_connected" );
|
|
SetDvar( "all_players_are_connected", "1" );
|
|
|
|
/# println( "ZM >> We have all players - START ZOMBIE LOGIC" ); #/
|
|
|
|
|
|
|
|
//Check to see if we should spawn some bots to help
|
|
if ( (1 == GetNumConnectedPlayers()) && (GetDvarInt( "scr_zm_enable_bots" )==1) )
|
|
{
|
|
level thread add_bots();
|
|
level flag::set("initial_players_connected");
|
|
}
|
|
else
|
|
{
|
|
players = GetPlayers();
|
|
if ( players.size == 1 )
|
|
{
|
|
level flag::set( "solo_game" );
|
|
level.solo_lives_given = 0;
|
|
foreach ( player in players )
|
|
{
|
|
player.lives = 0;
|
|
}
|
|
level zm::set_default_laststand_pistol( true );
|
|
}
|
|
|
|
level flag::set("initial_players_connected");
|
|
|
|
array::thread_all(GetPlayers(), &initialBlack);
|
|
|
|
while ( !AreTexturesLoaded() )
|
|
{
|
|
{wait(.05);};
|
|
}
|
|
|
|
if ( isdefined(level.added_initial_streamer_blackscreen) )
|
|
{
|
|
wait(level.added_initial_streamer_blackscreen);
|
|
}
|
|
|
|
//level flag::set( "start_zombie_round_logic" );
|
|
thread start_zombie_logic_in_x_sec( 3.0 );
|
|
}
|
|
|
|
set_intermission_point();
|
|
|
|
n_black_screen = 5.0;
|
|
level thread fade_out_intro_screen_zm( n_black_screen, 1.5, true );
|
|
wait n_black_screen;
|
|
|
|
// Reset the start time
|
|
level.n_gameplay_start_time = GetTime();
|
|
clientfield::set( "game_start_time", level.n_gameplay_start_time );
|
|
}
|
|
|
|
function initialBlack()
|
|
{
|
|
self CloseMenu( "InitialBlack" );
|
|
self OpenMenu( "InitialBlack" );
|
|
}
|
|
|
|
function initialBlackEnd()
|
|
{
|
|
self CloseMenu( "InitialBlack" );
|
|
// self clientfield::set_to_player( "sndLevelStartSnapOff", 1 );
|
|
}
|
|
|
|
|
|
|
|
function start_zombie_logic_in_x_sec( time_to_wait )
|
|
{
|
|
wait( time_to_wait );
|
|
level flag::set( "start_zombie_round_logic" );
|
|
}
|
|
|
|
|
|
function getAllOtherPlayers()
|
|
{
|
|
aliveplayers = [];
|
|
|
|
// Make a list of fully connected, non-spectating, alive players
|
|
for(i = 0; i < level.players.size; i++)
|
|
{
|
|
if ( !isdefined( level.players[i] ) )
|
|
continue;
|
|
player = level.players[i];
|
|
|
|
if ( player.sessionstate != "playing" || player == self )
|
|
continue;
|
|
|
|
aliveplayers[aliveplayers.size] = player;
|
|
}
|
|
return aliveplayers;
|
|
}
|
|
|
|
function updatePlayerNum( player )
|
|
{
|
|
if(!Isdefined(player.playernum))
|
|
{
|
|
if(player.team == "allies")
|
|
{
|
|
player.playernum = zm_utility::get_game_var("_team1_num");
|
|
zm_utility::set_game_var("_team1_num", player.playernum + 1);
|
|
}
|
|
else
|
|
{
|
|
player.playernum = zm_utility::get_game_var("_team2_num");
|
|
zm_utility::set_game_var("_team2_num", player.playernum + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getFreeSpawnpoint(spawnpoints, player)
|
|
{
|
|
// There are no valid spawnpoints in the map
|
|
if(!isdefined(spawnpoints))
|
|
{
|
|
/#
|
|
iprintlnbold( "ZM >> No free spawn points in map" );
|
|
#/
|
|
return undefined;
|
|
}
|
|
|
|
// only should happen on initial spawn.
|
|
|
|
if(!isdefined(game["spawns_randomized"]))
|
|
{
|
|
game["spawns_randomized"] = true;
|
|
|
|
spawnpoints = array::randomize(spawnpoints);
|
|
|
|
random_chance = randomint(100);
|
|
if(random_chance > 50)
|
|
{
|
|
zm_utility::set_game_var("side_selection", 1);
|
|
}
|
|
else
|
|
{
|
|
zm_utility::set_game_var("side_selection", 2);
|
|
}
|
|
}
|
|
|
|
side_selection = zm_utility::get_game_var("side_selection");
|
|
|
|
// used in vs. games where you switch sides on next round.
|
|
if( zm_utility::get_game_var("switchedsides"))
|
|
{
|
|
if(side_selection == 2)
|
|
{
|
|
side_selection = 1;
|
|
}
|
|
else if(side_selection == 1)
|
|
{
|
|
side_selection = 2;
|
|
}
|
|
}
|
|
|
|
if(IsDefined(player) && IsDefined(player.team))
|
|
{
|
|
i = 0;
|
|
while(IsDefined(spawnpoints) && i < spawnpoints.size)
|
|
{
|
|
If(side_selection == 1)
|
|
{
|
|
if(player.team != "allies" && (IsDefined(spawnpoints[i].script_int) && spawnpoints[i].script_int == 1))
|
|
{
|
|
ArrayRemoveValue(spawnpoints, spawnpoints[i]);
|
|
i=0;
|
|
}
|
|
else if(player.team == "allies" && (IsDefined(spawnpoints[i].script_int) && spawnpoints[i].script_int == 2))
|
|
{
|
|
ArrayRemoveValue(spawnpoints, spawnpoints[i]);
|
|
i=0;
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(player.team == "allies" && (IsDefined(spawnpoints[i].script_int) && spawnpoints[i].script_int == 1))
|
|
{
|
|
ArrayRemoveValue(spawnpoints, spawnpoints[i]);
|
|
i=0;
|
|
}
|
|
else if(player.team != "allies" && (IsDefined(spawnpoints[i].script_int) && spawnpoints[i].script_int == 2))
|
|
{
|
|
ArrayRemoveValue(spawnpoints, spawnpoints[i]);
|
|
i=0;
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
updatePlayerNum( player );
|
|
|
|
for( j = 0; j < spawnpoints.size; j++ )
|
|
{
|
|
if(!IsDefined(spawnpoints[j].en_num))
|
|
{
|
|
for( m = 0; m < spawnpoints.size; m++ )
|
|
{
|
|
spawnpoints[m].en_num = m;
|
|
}
|
|
}
|
|
|
|
if( spawnpoints[j].en_num == player.playernum)
|
|
{
|
|
return spawnpoints[j];
|
|
}
|
|
}
|
|
|
|
return spawnpoints[0];
|
|
}
|
|
|
|
|
|
function delete_in_createfx()
|
|
{
|
|
exterior_goals =struct::get_array( "exterior_goal", "targetname" );
|
|
for( i = 0; i < exterior_goals.size; i++ )
|
|
{
|
|
if( !IsDefined( exterior_goals[i].target ) ) // If the exterior_goal entity has no targets defined then return
|
|
{
|
|
continue;
|
|
}
|
|
targets = GetEntArray( exterior_goals[i].target, "targetname" ); // Grab all the pieces that are targeted by the exterior_goal
|
|
|
|
for( j = 0; j < targets.size; j++ ) // count total targets of exterior_goal
|
|
{
|
|
targets[j] zm_utility::self_delete();
|
|
}
|
|
}
|
|
|
|
if(isdefined(level.level_createfx_callback_thread))
|
|
{
|
|
level thread [[level.level_createfx_callback_thread]]();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function add_bots()
|
|
{
|
|
//Wait for the host!
|
|
host = util::GetHostPlayer();
|
|
while ( !IsDefined( host ) )
|
|
{
|
|
{wait(.05);};
|
|
host = util::GetHostPlayer();
|
|
}
|
|
|
|
wait( 4.0 );
|
|
|
|
//Then spawn bots
|
|
zbot_spawn();
|
|
SetDvar("bot_AllowMovement", "1");
|
|
SetDvar("bot_PressAttackBtn", "1");
|
|
SetDvar("bot_PressMeleeBtn", "1");
|
|
|
|
//Wait until bots are spawned
|
|
while( GetPlayers().size<2 )
|
|
{
|
|
{wait(.05);};
|
|
}
|
|
|
|
//Unfreeze all players
|
|
players = GetPlayers();
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
players[i] FreezeControls( false );
|
|
/# println(" Unfreeze controls 6"); #/
|
|
|
|
}
|
|
|
|
level.numberBotsAdded = 1;
|
|
level flag::set( "start_zombie_round_logic" );
|
|
}
|
|
|
|
function zbot_spawn()
|
|
{
|
|
player = util::GetHostPlayer();
|
|
|
|
//spawnPoints =struct::get_array( "initial_spawn_points", "targetname" );
|
|
//spawnPoint = getFreeSpawnpoint( spawnPoints, player );
|
|
|
|
bot = AddTestClient();
|
|
if ( !IsDefined( bot ) )
|
|
{
|
|
/# println( "Could not add test client" ); #/
|
|
return;
|
|
}
|
|
|
|
|
|
spawnPoint = bot zm_gametype::onFindValidSpawnPoint();
|
|
|
|
bot.pers["isBot"] = true;
|
|
bot.equipment_enabled = false;
|
|
yaw = spawnPoint.angles[1];
|
|
|
|
return bot;
|
|
}
|
|
|
|
function post_all_players_connected()
|
|
{
|
|
level thread end_game();
|
|
|
|
level flag::wait_till( "start_zombie_round_logic" );
|
|
|
|
zm_utility::increment_zm_dash_counter( "start_per_game", 1 );
|
|
zm_utility::increment_zm_dash_counter( "start_per_player", level.players.size );
|
|
zm_utility::upload_zm_dash_counters();
|
|
|
|
level.dash_counter_start_player_count = level.players.size;
|
|
/#
|
|
println( "sessions: mapname=", level.script, " gametype zom isserver 1 player_count=", GetPlayers().size );
|
|
#/
|
|
// Start the Zombie MODE!
|
|
level thread round_end_monitor();
|
|
|
|
if(!level.zombie_anim_intro)
|
|
{
|
|
if(isDefined(level._round_start_func))
|
|
{
|
|
level thread [[level._round_start_func]]();
|
|
}
|
|
}
|
|
|
|
level thread players_playing();
|
|
|
|
DisableGrenadeSuicide();
|
|
level.startInvulnerableTime = GetDvarInt( "player_deathInvulnerableTime" );
|
|
}
|
|
|
|
function start_zm_dash_counter_watchers()
|
|
{
|
|
level thread first_consumables_used_watcher();
|
|
level thread players_reached_rounds_counter_watcher();
|
|
}
|
|
|
|
function first_consumables_used_watcher()
|
|
{
|
|
level flag::init( "first_consumables_used" );
|
|
|
|
level flag::wait_till( "first_consumables_used" );
|
|
|
|
zm_utility::increment_zm_dash_counter( "first_consumables_used", 1 );
|
|
zm_utility::upload_zm_dash_counters();
|
|
}
|
|
|
|
function players_reached_rounds_counter_watcher()
|
|
{
|
|
while( true )
|
|
{
|
|
level waittill( "start_of_round" );
|
|
|
|
if( !IsDefined( level.dash_counter_round_reached_5 ) && level.round_number >= 5 )
|
|
{
|
|
level.dash_counter_round_reached_5 = true;
|
|
zm_utility::increment_zm_dash_counter( "reached_5", 1 );
|
|
}
|
|
|
|
if( !IsDefined( level.dash_counter_round_reached_10 ) && level.round_number >= 10 )
|
|
{
|
|
level.dash_counter_round_reached_10 = true;
|
|
zm_utility::increment_zm_dash_counter( "reached_10", 1 );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
function init_custom_ai_type()
|
|
{
|
|
//wait( 0.1 );
|
|
// waittillframeend;
|
|
|
|
if( isDefined( level.custom_ai_type ) )
|
|
{
|
|
for( i = 0; i < level.custom_ai_type.size; i++ )
|
|
{
|
|
[[ level.custom_ai_type[i] ]]();
|
|
}
|
|
}
|
|
}
|
|
|
|
function zombiemode_melee_miss()
|
|
{
|
|
if( isDefined( self.enemy.curr_pay_turret ) )
|
|
{
|
|
self.enemy doDamage( GetDvarInt( "ai_meleeDamage" ), self.origin, self, self, "none", "melee" );
|
|
}
|
|
}
|
|
|
|
/*------------------------------------
|
|
function chrisp - adding vo to track players ammo
|
|
------------------------------------*/
|
|
function player_track_ammo_count()
|
|
{
|
|
self notify( "stop_ammo_tracking" );
|
|
self endon( "disconnect" );
|
|
self endon( "stop_ammo_tracking" );
|
|
|
|
ammoLowCount = 0;
|
|
ammoOutCount = 0;
|
|
|
|
while ( 1 )
|
|
{
|
|
wait( .5 );
|
|
weapon = self getcurrentweapon();
|
|
|
|
if ( weapon == level.weaponNone || weapon.skiplowammovox )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( weapon.type == "grenade" )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( self GetAmmoCount( weapon ) > 5 || self laststand::player_is_in_laststand() )
|
|
{
|
|
ammoOutCount = 0;
|
|
ammoLowCount = 0;
|
|
continue;
|
|
}
|
|
|
|
if ( self GetAmmoCount( weapon ) > 0 )
|
|
{
|
|
if ( ammoLowCount < 1 )
|
|
{
|
|
self zm_audio::create_and_play_dialog( "general", "ammo_low" );
|
|
ammoLowCount++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ammoOutCount < 1 )
|
|
{
|
|
wait ( .5 );
|
|
|
|
if( (self getcurrentweapon() ) !== weapon ) //This prevents "ammo out" vo from playing in the case that we swap a weapon from the box.
|
|
{
|
|
continue;
|
|
}
|
|
|
|
self zm_audio::create_and_play_dialog( "general", "ammo_out" );
|
|
ammoOutCount++;
|
|
}
|
|
}
|
|
wait( 20 );
|
|
}
|
|
}
|
|
|
|
/*------------------------------------
|
|
function audio plays when more than 1 player connects
|
|
------------------------------------*/
|
|
function spawn_vo()
|
|
{
|
|
//not sure if we need this
|
|
wait(1);
|
|
|
|
players = GetPlayers();
|
|
|
|
//just pick a random player for now and play some vo
|
|
if(players.size > 1)
|
|
{
|
|
player = array::random(players);
|
|
index = zm_utility::get_player_index(player);
|
|
player thread spawn_vo_player(index,players.size);
|
|
}
|
|
|
|
}
|
|
|
|
function spawn_vo_player(index,num)
|
|
{
|
|
sound = "plr_" + index + "_vox_" + num +"play";
|
|
self PlaySoundWithNotify(sound, "sound_done");
|
|
self waittill("sound_done");
|
|
}
|
|
|
|
function precache_models()
|
|
{
|
|
if ( isDefined( level.precacheCustomCharacters ) )
|
|
{
|
|
self [[ level.precacheCustomCharacters ]]();
|
|
}
|
|
}
|
|
|
|
function init_shellshocks()
|
|
{
|
|
level.player_killed_shellshock = "zombie_death";
|
|
}
|
|
|
|
function init_strings()
|
|
{
|
|
zm_utility::add_zombie_hint( "undefined", &"ZOMBIE_UNDEFINED" );
|
|
|
|
// Random Treasure Chest
|
|
zm_utility::add_zombie_hint( "default_treasure_chest", &"ZOMBIE_RANDOM_WEAPON_COST" );
|
|
|
|
// Barrier Pieces
|
|
zm_utility::add_zombie_hint( "default_buy_barrier_piece_10", &"ZOMBIE_BUTTON_BUY_BACK_BARRIER_10" );
|
|
zm_utility::add_zombie_hint( "default_buy_barrier_piece_20", &"ZOMBIE_BUTTON_BUY_BACK_BARRIER_20" );
|
|
zm_utility::add_zombie_hint( "default_buy_barrier_piece_50", &"ZOMBIE_BUTTON_BUY_BACK_BARRIER_50" );
|
|
zm_utility::add_zombie_hint( "default_buy_barrier_piece_100", &"ZOMBIE_BUTTON_BUY_BACK_BARRIER_100" );
|
|
|
|
// REWARD Barrier Pieces
|
|
zm_utility::add_zombie_hint( "default_reward_barrier_piece", &"ZOMBIE_BUTTON_REWARD_BARRIER" );
|
|
|
|
// Areas
|
|
zm_utility::add_zombie_hint( "default_buy_area", &"ZOMBIE_BUTTON_BUY_OPEN_AREA_COST" );
|
|
}
|
|
|
|
function init_sounds()
|
|
{
|
|
zm_utility::add_sound( "end_of_round", "mus_zmb_round_over" );
|
|
zm_utility::add_sound( "end_of_game", "mus_zmb_game_over" ); //Had to remove this and add a music state switch so that we can add other musical elements.
|
|
zm_utility::add_sound( "chalk_one_up", "mus_zmb_chalk" );
|
|
zm_utility::add_sound( "purchase", "zmb_cha_ching" );
|
|
zm_utility::add_sound( "no_purchase", "zmb_no_cha_ching" );
|
|
|
|
// Zombification
|
|
// TODO need to vary these up
|
|
zm_utility::add_sound( "playerzombie_usebutton_sound", "zmb_zombie_vocals_attack" );
|
|
zm_utility::add_sound( "playerzombie_attackbutton_sound", "zmb_zombie_vocals_attack" );
|
|
zm_utility::add_sound( "playerzombie_adsbutton_sound", "zmb_zombie_vocals_attack" );
|
|
|
|
// Head gib
|
|
zm_utility::add_sound( "zombie_head_gib", "zmb_zombie_head_gib" );
|
|
|
|
// Blockers
|
|
zm_utility::add_sound( "rebuild_barrier_piece", "zmb_repair_boards" );
|
|
zm_utility::add_sound( "rebuild_barrier_metal_piece", "zmb_metal_repair" );
|
|
zm_utility::add_sound( "rebuild_barrier_hover", "zmb_boards_float" );
|
|
zm_utility::add_sound( "debris_hover_loop", "zmb_couch_loop" );
|
|
zm_utility::add_sound( "break_barrier_piece", "zmb_break_boards" );
|
|
zm_utility::add_sound( "grab_metal_bar", "zmb_bar_pull" );
|
|
zm_utility::add_sound( "break_metal_bar", "zmb_bar_break" );
|
|
zm_utility::add_sound( "drop_metal_bar", "zmb_bar_drop" );
|
|
zm_utility::add_sound("blocker_end_move", "zmb_board_slam");
|
|
zm_utility::add_sound( "barrier_rebuild_slam", "zmb_board_slam" );
|
|
zm_utility::add_sound( "bar_rebuild_slam", "zmb_bar_repair" );
|
|
zm_utility::add_sound( "zmb_rock_fix", "zmb_break_rock_barrier_fix" );
|
|
zm_utility::add_sound( "zmb_vent_fix", "evt_vent_slat_repair" );
|
|
zm_utility::add_sound ("zmb_barrier_debris_move", "zmb_barrier_debris_move");
|
|
|
|
// Doors
|
|
zm_utility::add_sound( "door_slide_open", "zmb_door_slide_open" );
|
|
zm_utility::add_sound( "door_rotate_open", "zmb_door_slide_open" );
|
|
|
|
// Debris
|
|
zm_utility::add_sound( "debris_move", "zmb_weap_wall" );
|
|
|
|
// Random Weapon Chest
|
|
zm_utility::add_sound( "open_chest", "zmb_lid_open" );
|
|
zm_utility::add_sound( "music_chest", "zmb_music_box" );
|
|
zm_utility::add_sound( "close_chest", "zmb_lid_close" );
|
|
|
|
// Weapons on walls
|
|
zm_utility::add_sound( "weapon_show", "zmb_weap_wall" );
|
|
|
|
zm_utility::add_sound( "break_stone", "evt_break_stone" );
|
|
}
|
|
|
|
function init_levelvars()
|
|
{
|
|
// Variables
|
|
// used to a check in last stand for players to become zombies
|
|
level.is_zombie_level = true;
|
|
level.default_laststandpistol = GetWeapon( "pistol_standard" );
|
|
level.default_solo_laststandpistol = GetWeapon( "pistol_standard_upgraded" );
|
|
level.super_ee_weapon = GetWeapon( "pistol_burst" );
|
|
level.laststandpistol = level.default_laststandpistol; // so we dont get the uber colt when we're knocked out
|
|
level.start_weapon = level.default_laststandpistol;
|
|
level.first_round = true;
|
|
level.start_round = GetGametypeSetting( "startRound" );
|
|
level.round_number = level.start_round;
|
|
level.enable_magic = GetGametypeSetting( "magic" );
|
|
level.headshots_only = GetGametypeSetting( "headshotsonly" );
|
|
level.player_starting_points = level.round_number * 500;
|
|
level.round_start_time = 0;
|
|
level.pro_tips_start_time = 0;
|
|
level.intermission = false;
|
|
level.dog_intermission = false;
|
|
level.zombie_total = 0; // Total number of zombies left to spawn
|
|
level.zombie_respawns = 0; // Total number of zombies that need to be respawned due to cleanup
|
|
level.total_zombies_killed = 0;
|
|
level.hudelem_count = 0;
|
|
level.zm_loc_types = [];
|
|
level.zm_loc_types[ "zombie_location" ] = []; // List of normal zombie spawners (other types will be added in the zone manager)
|
|
|
|
level.zm_variant_type_max = [];
|
|
level.zm_variant_type_max[ "walk" ] = [];
|
|
level.zm_variant_type_max[ "run" ] = [];
|
|
level.zm_variant_type_max[ "sprint" ] = [];
|
|
level.zm_variant_type_max[ "super_sprint" ] = [];
|
|
level.zm_variant_type_max[ "walk" ][ "down" ] = 14;
|
|
level.zm_variant_type_max[ "walk" ][ "up" ] = 16;
|
|
level.zm_variant_type_max[ "run" ][ "down" ] = 13;
|
|
level.zm_variant_type_max[ "run" ][ "up" ] = 12;
|
|
level.zm_variant_type_max[ "sprint" ][ "down" ] = 9;
|
|
level.zm_variant_type_max[ "sprint" ][ "up" ] = 8;
|
|
level.zm_variant_type_max[ "super_sprint" ][ "down" ] = 1;
|
|
level.zm_variant_type_max[ "super_sprint" ][ "up" ] = 1;
|
|
level.zm_variant_type_max[ "burned" ][ "down" ] = 1;
|
|
level.zm_variant_type_max[ "burned" ][ "up" ] = 1;
|
|
level.zm_variant_type_max[ "jump_pad_super_sprint" ][ "down" ] = 1;
|
|
level.zm_variant_type_max[ "jump_pad_super_sprint" ][ "up" ] = 1;
|
|
|
|
level.current_zombie_array = [];
|
|
level.current_zombie_count = 0;
|
|
level.zombie_total_subtract = 0;
|
|
level.destructible_callbacks = [];
|
|
|
|
foreach( team in level.teams )
|
|
{
|
|
if(!isdefined(level.zombie_vars[ team ]))level.zombie_vars[ team ]=[];
|
|
}
|
|
|
|
difficulty = 1;
|
|
column = int(difficulty) + 1;
|
|
|
|
//#######################################################################
|
|
// zombie_utility::set_zombie_var( identifier, value, float, column );
|
|
|
|
// AI
|
|
zombie_utility::set_zombie_var( "zombie_health_increase", 100, false, column ); // cumulatively add this to the zombies' starting health each round (up to round 10)
|
|
zombie_utility::set_zombie_var( "zombie_health_increase_multiplier",0.1, true, column ); // after round 10 multiply the zombies' starting health by this amount
|
|
zombie_utility::set_zombie_var( "zombie_health_start", 150, false, column ); // starting health of a zombie at round 1
|
|
zombie_utility::set_zombie_var( "zombie_spawn_delay", 2.0, true, column ); // Time to wait between spawning zombies. This is modified based on the round number.
|
|
zombie_utility::set_zombie_var( "zombie_new_runner_interval", 10, false, column ); // Interval between changing walkers who are too far away into runners
|
|
zombie_utility::set_zombie_var( "zombie_move_speed_multiplier", 4, false, column ); // Multiply by the round number to give the base speed value. 0-40 = walk, 41-70 = run, 71+ = sprint
|
|
zombie_utility::set_zombie_var( "zombie_move_speed_multiplier_easy", 2, false, column ); // Multiply by the round number to give the base speed value. 0-40 = walk, 41-70 = run, 71+ = sprint
|
|
|
|
zombie_utility::set_zombie_var( "zombie_max_ai", 24, false, column ); // Base number of zombies per player (modified by round #)
|
|
zombie_utility::set_zombie_var( "zombie_ai_per_player", 6, false, column ); // additional zombie modifier for each player in the game
|
|
zombie_utility::set_zombie_var( "below_world_check", -1000 ); // Check height to see if a zombie has fallen through the world.
|
|
|
|
// Round
|
|
zombie_utility::set_zombie_var( "spectators_respawn", true ); // Respawn in the spectators in between rounds
|
|
zombie_utility::set_zombie_var( "zombie_use_failsafe", true ); // Will slowly kill zombies who are stuck
|
|
zombie_utility::set_zombie_var( "zombie_between_round_time", 10 ); // How long to pause after the round ends
|
|
zombie_utility::set_zombie_var( "zombie_intermission_time", 15 ); // Length of time to show the end of game stats
|
|
zombie_utility::set_zombie_var( "game_start_delay", 0, false, column ); // How much time to give people a break before starting spawning
|
|
|
|
// Life and death
|
|
zombie_utility::set_zombie_var( "player_base_health", 100 ); // Base health of a player
|
|
|
|
zombie_utility::set_zombie_var( "penalty_no_revive", 0.10, true, column ); // Percentage of money you lose if you let a teammate die
|
|
zombie_utility::set_zombie_var( "penalty_died", 0.0, true, column ); // Percentage of money lost if you die
|
|
zombie_utility::set_zombie_var( "penalty_downed", 0.05, true, column ); // Percentage of money lost if you go down // ww: told to remove downed point loss
|
|
|
|
zombie_utility::set_zombie_var( "zombie_score_kill_4player", 50 ); // Individual Points for a zombie kill in a 4 player game
|
|
zombie_utility::set_zombie_var( "zombie_score_kill_3player", 50 ); // Individual Points for a zombie kill in a 3 player game
|
|
zombie_utility::set_zombie_var( "zombie_score_kill_2player", 50 ); // Individual Points for a zombie kill in a 2 player game
|
|
zombie_utility::set_zombie_var( "zombie_score_kill_1player", 50 ); // Individual Points for a zombie kill in a 1 player game
|
|
|
|
zombie_utility::set_zombie_var( "zombie_score_damage_normal", 10 ); // points gained for a hit with a non-automatic weapon
|
|
zombie_utility::set_zombie_var( "zombie_score_damage_light", 10 ); // points gained for a hit with an automatic weapon
|
|
|
|
zombie_utility::set_zombie_var( "zombie_score_bonus_melee", 80 ); // Bonus points for a melee kill
|
|
zombie_utility::set_zombie_var( "zombie_score_bonus_head", 50 ); // Bonus points for a head shot kill
|
|
zombie_utility::set_zombie_var( "zombie_score_bonus_neck", 20 ); // Bonus points for a neck shot kill
|
|
zombie_utility::set_zombie_var( "zombie_score_bonus_torso", 10 ); // Bonus points for a torso shot kill
|
|
zombie_utility::set_zombie_var( "zombie_score_bonus_burn", 10 ); // Bonus points for a burn kill
|
|
|
|
zombie_utility::set_zombie_var( "zombie_flame_dmg_point_delay", 500 );
|
|
|
|
zombie_utility::set_zombie_var( "zombify_player", false ); // Default to not zombify the player till further support
|
|
|
|
if ( IsSplitScreen() )
|
|
{
|
|
zombie_utility::set_zombie_var( "zombie_timer_offset", 280 ); // hud offsets
|
|
}
|
|
|
|
level thread init_player_levelvars();
|
|
|
|
level.gamedifficulty = GetGametypeSetting( "zmDifficulty" );
|
|
|
|
if( level.gamedifficulty == 0 ) //easy
|
|
{
|
|
level.zombie_move_speed = level.round_number * level.zombie_vars["zombie_move_speed_multiplier_easy"];
|
|
}
|
|
else //normal
|
|
{
|
|
level.zombie_move_speed = level.round_number * level.zombie_vars["zombie_move_speed_multiplier"];
|
|
}
|
|
|
|
//Make sure we only have walker zombies in round 1
|
|
if ( level.round_number == 1 )
|
|
{
|
|
level.zombie_move_speed = 1;
|
|
}
|
|
|
|
level.speed_change_max = 0;
|
|
level.speed_change_num = 0;
|
|
|
|
set_round_number( level.round_number );
|
|
}
|
|
|
|
function init_player_levelvars()
|
|
{
|
|
level flag::wait_till( "start_zombie_round_logic" );
|
|
|
|
difficulty = 1;
|
|
column = int(difficulty) + 1;
|
|
|
|
for(i = 0; i < 8; i ++)
|
|
{
|
|
points = 500;
|
|
|
|
if(i > 3)
|
|
{
|
|
points = 3000; // Dont change the behavior of grief.
|
|
}
|
|
|
|
points = zombie_utility::set_zombie_var( ("zombie_score_start_"+ (i+1) +"p"), points, false, column );
|
|
}
|
|
}
|
|
|
|
function init_dvars()
|
|
{
|
|
//t6.5todo: move these dvars out of script, dangerous to leave them here like this
|
|
|
|
if( GetDvarString( "zombie_debug" ) == "" )
|
|
{
|
|
SetDvar( "zombie_debug", "0" );
|
|
}
|
|
|
|
if( GetDvarString( "scr_zm_enable_bots" ) == "" )
|
|
{
|
|
SetDvar( "scr_zm_enable_bots", "0" );
|
|
}
|
|
|
|
if( GetDvarString( "zombie_cheat" ) == "" )
|
|
{
|
|
SetDvar( "zombie_cheat", "0" );
|
|
}
|
|
|
|
if ( GetDvarString("zombiemode_debug_zombie_count") == "" )
|
|
{
|
|
SetDvar("zombiemode_debug_zombie_count", "0");
|
|
}
|
|
|
|
if ( level.script != "zombie_cod5_prototype" )
|
|
{
|
|
SetDvar( "magic_chest_movable", "1" );
|
|
}
|
|
|
|
SetDvar( "revive_trigger_radius", "75" );
|
|
|
|
SetDvar( "scr_deleteexplosivesonspawn", "0" );
|
|
}
|
|
|
|
|
|
function init_function_overrides()
|
|
{
|
|
level.callbackPlayerDamage = &Callback_PlayerDamage;
|
|
level.overridePlayerDamage = &player_damage_override; //_cheat;
|
|
level.callbackPlayerKilled = &player_killed_override;
|
|
|
|
level.playerlaststand_func = &player_laststand;
|
|
level.callbackPlayerLastStand = &Callback_PlayerLastStand;
|
|
|
|
level.prevent_player_damage = &player_prevent_damage;
|
|
|
|
level.callbackActorKilled = &actor_killed_override;
|
|
level.callbackActorDamage = &actor_damage_override_wrapper;
|
|
|
|
level.callbackVehicleDamage = &vehicle_damage_override;
|
|
level.callbackVehicleKilled = &globallogic_vehicle::Callback_VehicleKilled;
|
|
level.callbackVehicleRadiusDamage = &globallogic_vehicle::Callback_VehicleRadiusDamage;
|
|
|
|
level.custom_introscreen = &zombie_intro_screen;
|
|
level.custom_intermission = &player_intermission;
|
|
|
|
level.global_damage_func = &zm_spawner::zombie_damage;
|
|
level.global_damage_func_ads = &zm_spawner::zombie_damage_ads;
|
|
|
|
level.reset_clientdvars = &onPlayerConnect_clientDvars;
|
|
|
|
level.zombie_last_stand = &last_stand_pistol_swap;
|
|
level.zombie_last_stand_pistol_memory = &last_stand_save_pistol_ammo;
|
|
level.zombie_last_stand_ammo_return = &last_stand_restore_pistol_ammo;
|
|
|
|
level.player_becomes_zombie = &zombify_player;
|
|
|
|
level.validate_enemy_path_length = &zm_utility::default_validate_enemy_path_length;
|
|
}
|
|
|
|
function Callback_PlayerLastStand( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration )
|
|
{
|
|
self endon( "disconnect" );
|
|
//self Callback("on_player_last_stand");
|
|
zm_laststand::PlayerLastStand( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration );
|
|
}
|
|
|
|
function CodeCallback_DestructibleEvent( event, param1, param2, param3 )
|
|
{
|
|
if( event == "broken" )
|
|
{
|
|
notify_type = param1;
|
|
attacker = param2;
|
|
weapon = param3;
|
|
|
|
if ( IsDefined( level.destructible_callbacks[ notify_type ] ) )
|
|
{
|
|
self thread [[level.destructible_callbacks[ notify_type ]]]( notify_type, attacker );
|
|
}
|
|
|
|
self notify( event, notify_type, attacker );
|
|
}
|
|
else if( event == "breakafter" )
|
|
{
|
|
piece = param1;
|
|
time = param2;
|
|
damage = param3;
|
|
self thread breakAfter( time, damage, piece );
|
|
}
|
|
}
|
|
|
|
function breakAfter( time, damage, piece )
|
|
{
|
|
self notify( "breakafter" );
|
|
self endon( "breakafter" );
|
|
|
|
wait time;
|
|
|
|
// this does not work in mp. DoDamage does not take a piece for mp.
|
|
self dodamage( damage, self.origin, undefined, /*piece*/undefined );
|
|
}
|
|
|
|
function Callback_PlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal )
|
|
{
|
|
startedInLastStand = 0;
|
|
if ( isPlayer(self) )
|
|
{
|
|
startedInLastStand = self laststand::player_is_in_laststand();
|
|
}
|
|
|
|
/# println( "ZM Callback_PlayerDamage"+iDamage+"\n"); #/
|
|
if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && (eAttacker.sessionteam == self.sessionteam) && !eAttacker HasPerk( "specialty_playeriszombie" ) && !( isdefined( self.is_zombie ) && self.is_zombie ) )
|
|
{
|
|
self process_friendly_fire_callbacks( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex );
|
|
if ( self != eAttacker )
|
|
{
|
|
//one player shouldn't damage another player, grenades, airstrikes called in by another player
|
|
/# println("Exiting - players can't hurt each other."); #/
|
|
|
|
|
|
return;
|
|
}
|
|
else if ( sMeansOfDeath != "MOD_GRENADE_SPLASH"
|
|
&& sMeansOfDeath != "MOD_GRENADE"
|
|
&& sMeansOfDeath != "MOD_EXPLOSIVE"
|
|
&& sMeansOfDeath != "MOD_PROJECTILE"
|
|
&& sMeansOfDeath != "MOD_PROJECTILE_SPLASH"
|
|
&& sMeansOfDeath != "MOD_BURNED"
|
|
&& sMeansOfDeath != "MOD_SUICIDE" )
|
|
{
|
|
/# println("Exiting - damage type verbotten."); #/
|
|
//player should be able to damage they're selves with grenades and stuff
|
|
//otherwise don't damage the player, so like airstrikes won't kill the player
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Notify the player of a zombie swipe if the persistent Insta Kill upgrade is active
|
|
if( ( isdefined( level.pers_upgrade_insta_kill ) && level.pers_upgrade_insta_kill ) )
|
|
{
|
|
self zm_pers_upgrades_functions::pers_insta_kill_melee_swipe( sMeansOfDeath, eAttacker );
|
|
}
|
|
|
|
if( IsDefined( self.overridePlayerDamage ) )
|
|
{
|
|
iDamage = self [[self.overridePlayerDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime );
|
|
}
|
|
else if( IsDefined( level.overridePlayerDamage ) )
|
|
{
|
|
iDamage = self [[level.overridePlayerDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime );
|
|
}
|
|
|
|
Assert(IsDefined(iDamage), "You must return a value from a damage override function.");
|
|
|
|
// self Callback("on_player_damage");
|
|
|
|
if (( isdefined( self.magic_bullet_shield ) && self.magic_bullet_shield ))
|
|
{
|
|
// save out and restore the maxHealth, because setting health below modifies it
|
|
maxHealth = self.maxHealth;
|
|
|
|
// increase health by damage, because it will be subtracted back out below in finishActorDamage
|
|
self.health += iDamage;
|
|
|
|
// restore the maxHealth to what it was
|
|
self.maxHealth = maxHealth;
|
|
}
|
|
|
|
// DtP: When player is diving to prone away from the grenade, the damage is reduced
|
|
|
|
// player is diving
|
|
if( isdefined( self.divetoprone ) && self.divetoprone == 1 )
|
|
{
|
|
// grenade splash damage
|
|
if( sMeansOfDeath == "MOD_GRENADE_SPLASH" )
|
|
{
|
|
// if the player is at least 32 units away
|
|
dist = Distance2d(vPoint, self.origin);
|
|
if( dist > 32 )
|
|
{
|
|
// if player is diving away
|
|
dot_product = vectordot( AnglesToForward( self.angles ), vDir );
|
|
if( dot_product > 0 )
|
|
{
|
|
// grenade is behind player
|
|
iDamage = int( iDamage * 0.5 ); // halves damage
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/# println("CB PD"); #/
|
|
|
|
// players can only hurt themselves, zombie players can hurt any other player and be hurt by human players
|
|
/* if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && !eAttacker HasPerk( "specialty_playeriszombie" ) && !IS_TRUE( self.is_zombie ) )
|
|
{
|
|
if ( self != eAttacker )
|
|
{
|
|
//one player shouldn't damage another player, grenades, airstrikes called in by another player
|
|
println("Exiting - players can't hurt each other.");
|
|
return;
|
|
}
|
|
else if ( sMeansOfDeath != "MOD_GRENADE_SPLASH"
|
|
&& sMeansOfDeath != "MOD_GRENADE"
|
|
&& sMeansOfDeath != "MOD_EXPLOSIVE"
|
|
&& sMeansOfDeath != "MOD_PROJECTILE"
|
|
&& sMeansOfDeath != "MOD_PROJECTILE_SPLASH"
|
|
&& sMeansOfDeath != "MOD_BURNED"
|
|
&& sMeansOfDeath != "MOD_SUICIDE" )
|
|
{
|
|
println("Exiting - damage type verbotten.");
|
|
//player should be able to damage they're selves with grenades and stuff
|
|
//otherwise don't damage the player, so like airstrikes won't kill the player
|
|
return;
|
|
}
|
|
}*/
|
|
|
|
if ( isdefined( level.prevent_player_damage ) )
|
|
{
|
|
if ( self [[ level.prevent_player_damage ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
iDFlags = iDFlags | level.iDFLAGS_NO_KNOCKBACK;
|
|
|
|
//damage should have been reduced to 0 if it really was a riotshield hit
|
|
if( iDamage > 0 && sHitLoc == "riotshield" )
|
|
{
|
|
sHitLoc = "torso_upper";
|
|
}
|
|
|
|
/# PrintLn("Finishplayerdamage wrapper."); #/
|
|
wasDowned = 0;
|
|
if ( isPlayer(self))
|
|
{
|
|
wasDowned = !startedInLastStand && self laststand::player_is_in_laststand();
|
|
}
|
|
|
|
/#
|
|
if(IsDefined(eAttacker))
|
|
{
|
|
Record3DText( "D:" + iDamage + " H: " + self.health + " A: " + eAttacker GetEntityNumber(), self.origin, ( 1, 0, 0 ), "Script", self );
|
|
}
|
|
else
|
|
{
|
|
Record3DText( "D:" + iDamage + " H: " + self.health + " A: undefined", self.origin, ( 1, 0, 0 ), "Script", self );
|
|
}
|
|
#/
|
|
|
|
self finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal );
|
|
bb::logdamage(eattacker, self, weapon, idamage, smeansofdeath, shitloc, self.Health <= 0, wasDowned);
|
|
}
|
|
|
|
function finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal )
|
|
{
|
|
self finishPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, vSurfaceNormal );
|
|
|
|
// the MP version of finishPlayerDamage does not take 11 parameters
|
|
// the 11 parameter version in SP does not take these parameters (10 is modelIndex and 11 is pOffsetTime)
|
|
//surface = "flesh";
|
|
//self finishPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, surface );
|
|
|
|
}
|
|
|
|
function register_player_friendly_fire_callback( callback )
|
|
{
|
|
if (!isdefined(level.player_friendly_fire_callbacks))
|
|
level.player_friendly_fire_callbacks = [];
|
|
level.player_friendly_fire_callbacks[level.player_friendly_fire_callbacks.size] = callback;
|
|
}
|
|
|
|
function process_friendly_fire_callbacks( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex )
|
|
{
|
|
if (isdefined(level.player_friendly_fire_callbacks))
|
|
{
|
|
foreach( callback in level.player_friendly_fire_callbacks )
|
|
{
|
|
self [[callback]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex );
|
|
}
|
|
}
|
|
}
|
|
|
|
function init_flags()
|
|
{
|
|
level flag::init( "solo_game" );
|
|
level flag::init( "start_zombie_round_logic" );
|
|
level flag::init( "start_encounters_match_logic" );
|
|
level flag::init( "spawn_point_override" );
|
|
level flag::init( "crawler_round" );
|
|
level flag::init( "spawn_zombies", true );
|
|
level flag::init( "special_round" );
|
|
level flag::init( "dog_round" );
|
|
level flag::init( "raps_round" );
|
|
level flag::init( "begin_spawning" );
|
|
level flag::init( "end_round_wait" );
|
|
level flag::init( "wait_and_revive" );
|
|
level flag::init( "instant_revive" );
|
|
level flag::init( "initial_blackscreen_passed" );
|
|
level flag::init( "initial_players_connected" );
|
|
|
|
level flag::init( "power_on" );
|
|
//DCS: this will init all zone controlling power switch flags.
|
|
power_trigs = GetEntArray( "use_elec_switch", "targetname" );
|
|
foreach(trig in power_trigs)
|
|
{
|
|
if(IsDefined(trig.script_int))
|
|
{
|
|
level flag::init("power_on" + trig.script_int);
|
|
}
|
|
}
|
|
}
|
|
|
|
function init_client_field_callback_funcs()
|
|
{
|
|
// Client fields for actors
|
|
|
|
clientfield::register("actor", "zombie_riser_fx", 1, 1, "int");
|
|
|
|
if ( ( isdefined( level.use_water_risers ) && level.use_water_risers ) )
|
|
{
|
|
clientfield::register("actor", "zombie_riser_fx_water", 1, 1, "int");
|
|
}
|
|
|
|
if ( ( isdefined( level.use_foliage_risers ) && level.use_foliage_risers ) )
|
|
{
|
|
clientfield::register("actor", "zombie_riser_fx_foliage", 1, 1, "int");
|
|
}
|
|
|
|
if ( ( isdefined( level.use_low_gravity_risers ) && level.use_low_gravity_risers ) )
|
|
{
|
|
clientfield::register("actor", "zombie_riser_fx_lowg", 1, 1, "int");
|
|
}
|
|
|
|
clientfield::register("actor", "zombie_has_eyes", 1, 1, "int");
|
|
clientfield::register("actor", "zombie_ragdoll_explode", 1, 1, "int");
|
|
clientfield::register("actor", "zombie_gut_explosion", 1, 1, "int");
|
|
clientfield::register("actor", "sndZombieContext", (0 - 1), 1, "int");
|
|
clientfield::register("actor", "zombie_keyline_render", 1, 1, "int");
|
|
|
|
bits = 4;
|
|
trigs = GetEntArray( "use_elec_switch", "targetname" );
|
|
if ( IsDefined( trigs ) )
|
|
{
|
|
bits = GetMinBitCountForNum( trigs.size + 1 );
|
|
}
|
|
clientfield::register("world", "zombie_power_on", 1, bits, "int");
|
|
clientfield::register("world", "zombie_power_off", 1, bits, "int");
|
|
|
|
clientfield::register("world", "round_complete_time", 1, 20, "int");
|
|
clientfield::register("world", "round_complete_num", 1, 8, "int");
|
|
clientfield::register("world", "game_end_time", 1, 20, "int");
|
|
clientfield::register("world", "quest_complete_time", 1, 20, "int");
|
|
clientfield::register("world", "game_start_time", 15001, 20, "int" );
|
|
}
|
|
|
|
function init_fx()
|
|
{
|
|
level.createfx_callback_thread = &delete_in_createfx;
|
|
|
|
// level._effect["wood_chunk_destory"] = "_t6/impacts/fx_large_woodhit" ;
|
|
level._effect["fx_zombie_bar_break"] = "_t6/maps/zombie/fx_zombie_bar_break";
|
|
level._effect["fx_zombie_bar_break_lite"] = "_t6/maps/zombie/fx_zombie_bar_break_lite";
|
|
|
|
if ( !( isdefined( level.FX_exclude_edge_fog ) && level.FX_exclude_edge_fog ) )
|
|
{
|
|
level._effect["edge_fog"] = "_t6/maps/zombie/fx_fog_zombie_amb";
|
|
}
|
|
|
|
level._effect["chest_light"] = "zombie/fx_weapon_box_open_glow_zmb";
|
|
level._effect["chest_light_closed"] = "zombie/fx_weapon_box_closed_glow_zmb";
|
|
|
|
if ( !( isdefined( level.FX_exclude_default_eye_glow ) && level.FX_exclude_default_eye_glow ) )
|
|
{
|
|
level._effect["eye_glow"] = "zombie/fx_glow_eye_orange";
|
|
}
|
|
|
|
level._effect["headshot"] = "zombie/fx_bul_flesh_head_fatal_zmb";
|
|
level._effect["headshot_nochunks"] = "zombie/fx_bul_flesh_head_nochunks_zmb";
|
|
level._effect["bloodspurt"] = "zombie/fx_bul_flesh_neck_spurt_zmb";
|
|
|
|
if ( !( isdefined( level.FX_exclude_tesla_head_light ) && level.FX_exclude_tesla_head_light ) )
|
|
{
|
|
level._effect["tesla_head_light"] = "_t6/maps/zombie/fx_zombie_tesla_neck_spurt";
|
|
}
|
|
level._effect["zombie_guts_explosion"] = "zombie/fx_blood_torso_explo_lg_zmb";
|
|
|
|
|
|
level._effect["rise_burst_water"] = "zombie/fx_spawn_dirt_hand_burst_zmb";
|
|
level._effect["rise_billow_water"] = "zombie/fx_spawn_dirt_body_billowing_zmb";
|
|
level._effect["rise_dust_water"] = "zombie/fx_spawn_dirt_body_dustfalling_zmb";
|
|
|
|
level._effect["rise_burst"] = "zombie/fx_spawn_dirt_hand_burst_zmb";
|
|
level._effect["rise_billow"] = "zombie/fx_spawn_dirt_body_billowing_zmb";
|
|
level._effect["rise_dust"] = "zombie/fx_spawn_dirt_body_dustfalling_zmb";
|
|
|
|
level._effect["fall_burst"] = "zombie/fx_spawn_dirt_hand_burst_zmb";
|
|
level._effect["fall_billow"] = "zombie/fx_spawn_dirt_body_billowing_zmb";
|
|
level._effect["fall_dust"] = "zombie/fx_spawn_dirt_body_dustfalling_zmb";
|
|
|
|
// Flamethrower
|
|
level._effect["character_fire_death_sm"] = "zombie/fx_fire_torso_zmb";
|
|
level._effect["character_fire_death_torso"] = "zombie/fx_fire_torso_zmb";
|
|
|
|
if ( !( isdefined( level.fx_exclude_default_explosion ) && level.fx_exclude_default_explosion ) )
|
|
{
|
|
level._effect["def_explosion"] = "_t6/explosions/fx_default_explosion";
|
|
}
|
|
// level._effect["betty_explode"] = "_t6/weapon/bouncing_betty/fx_explosion_betty_generic";
|
|
|
|
// level._effect["default_weapon_glow"] = "_t6/maps/zombie/fx_zmb_tranzit_weapon_glow";
|
|
|
|
if ( !( isdefined( level.disable_fx_upgrade_aquired ) && level.disable_fx_upgrade_aquired ) )
|
|
{
|
|
level._effect["upgrade_aquired"] = "_t6/maps/zombie/fx_zmb_tanzit_upgrade";
|
|
}
|
|
}
|
|
|
|
// Handles the intro screen
|
|
function zombie_intro_screen( string1, string2, string3, string4, string5 )
|
|
{
|
|
level flag::wait_till( "start_zombie_round_logic" );
|
|
}
|
|
|
|
function players_playing()
|
|
{
|
|
// initialize level.players_playing
|
|
players = GetPlayers();
|
|
level.players_playing = players.size;
|
|
|
|
wait( 20 );
|
|
|
|
players = GetPlayers();
|
|
level.players_playing = players.size;
|
|
}
|
|
|
|
|
|
//
|
|
// NETWORK SECTION ====================================================================== //
|
|
//
|
|
|
|
function onPlayerConnect_clientDvars()
|
|
{
|
|
self SetClientCompass( 0 );
|
|
self SetClientThirdPerson( 0 );
|
|
self resetFov();
|
|
self SetClientThirdPersonAngle( 0 );
|
|
self SetClientUIVisibilityFlag( "weapon_hud_visible", 1 );
|
|
self SetClientMiniScoreboardHide( 1 );
|
|
self SetClientHUDHardcore( 0 );
|
|
self SetClientPlayerPushAmount( 1 );
|
|
|
|
self SetDepthOfField( 0, 0, 512, 4000, 4, 0 );
|
|
|
|
self zm_laststand::player_getup_setup();
|
|
}
|
|
|
|
|
|
|
|
function checkForAllDead(excluded_player)
|
|
{
|
|
players = GetPlayers();
|
|
count = 0;
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
if(isDefined(excluded_player) && excluded_player == players[i])
|
|
{
|
|
continue;
|
|
}
|
|
if( !(players[i] laststand::player_is_in_laststand()) && !(players[i].sessionstate == "spectator") )
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if( count==0 && !( isdefined( level.no_end_game_check ) && level.no_end_game_check ) )
|
|
{
|
|
level notify( "end_game" );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Runs when the player spawns into the map
|
|
// self is the player.surprise!
|
|
//
|
|
function onPlayerSpawned()
|
|
{
|
|
self endon( "disconnect" );
|
|
self notify("stop_onPlayerSpawned");
|
|
self endon("stop_onPlayerSpawned");
|
|
|
|
for( ;; )
|
|
{
|
|
self waittill( "spawned_player" );
|
|
|
|
if(!( isdefined( level.host_ended_game ) && level.host_ended_game ))
|
|
{
|
|
self freezecontrols( false );
|
|
/# println(" Unfreeze controls 7"); #/
|
|
|
|
}
|
|
self.hits = 0;
|
|
|
|
self zm_utility::init_player_offhand_weapons();
|
|
|
|
lethal_grenade = self zm_utility::get_player_lethal_grenade();
|
|
if( !self HasWeapon( lethal_grenade ) )
|
|
{
|
|
self GiveWeapon( lethal_grenade );
|
|
self SetWeaponAmmoClip( lethal_grenade, 0 );
|
|
}
|
|
|
|
self RecordPlayerReviveZombies( self );
|
|
|
|
/#
|
|
if ( GetDvarInt( "zombie_cheat" ) >= 1 && GetDvarInt( "zombie_cheat" ) <= 3 )
|
|
{
|
|
self EnableInvulnerability();
|
|
}
|
|
#/
|
|
|
|
self SetActionSlot( 3, "altMode" );
|
|
self PlayerKnockback( false );
|
|
|
|
self SetClientThirdPerson( 0 );
|
|
self resetFov();
|
|
self SetClientThirdPersonAngle( 0 );
|
|
|
|
self SetDepthOfField( 0, 0, 512, 4000, 4, 0 );
|
|
|
|
self cameraactivate(false);
|
|
|
|
self.num_perks = 0;
|
|
self.on_lander_last_stand = undefined;
|
|
self setblur(0, 0.1);
|
|
self.zmbDialogQueue = [];
|
|
self.zmbDialogActive = false;
|
|
self.zmbDialogGroups = [];
|
|
self.zmbDialogGroup = "";
|
|
|
|
if ( ( isdefined( level.player_out_of_playable_area_monitor ) && level.player_out_of_playable_area_monitor ) )
|
|
{
|
|
self thread player_out_of_playable_area_monitor();
|
|
}
|
|
|
|
if ( ( isdefined( level.player_too_many_weapons_monitor ) && level.player_too_many_weapons_monitor ) )
|
|
{
|
|
self thread [[level.player_too_many_weapons_monitor_func]]();
|
|
}
|
|
|
|
if ( ( isdefined( level.player_too_many_players_check ) && level.player_too_many_players_check ) )
|
|
{
|
|
level thread [[level.player_too_many_players_check_func]]();
|
|
}
|
|
|
|
self.disabled_perks = [];
|
|
|
|
if( isdefined( self.player_initialized ) )
|
|
{
|
|
if( self.player_initialized == false )
|
|
{
|
|
self.player_initialized = true;
|
|
|
|
//t6.5todo self freezecontrols( true ); // first spawn only, intro_black_screen will pull them out of it
|
|
|
|
self giveweapon( self zm_utility::get_player_lethal_grenade() );
|
|
self setweaponammoclip( self zm_utility::get_player_lethal_grenade(), 0);
|
|
self SetClientUIVisibilityFlag( "weapon_hud_visible", 1 );
|
|
self SetClientMiniScoreboardHide( 0 );
|
|
// ww: set the is_drinking variable
|
|
self.is_drinking = 0;
|
|
|
|
self thread player_zombie_breadcrumb();
|
|
|
|
self thread player_monitor_travel_dist();
|
|
self thread player_monitor_time_played();
|
|
|
|
if(isDefined(level.custom_player_track_ammo_count))
|
|
{
|
|
self thread [[level.custom_player_track_ammo_count]]();
|
|
}
|
|
else
|
|
{
|
|
self thread player_track_ammo_count();
|
|
}
|
|
|
|
self thread zm_utility::shock_onpain();
|
|
|
|
self thread player_grenade_watcher();
|
|
self laststand::revive_hud_create();
|
|
|
|
if(isDefined(level.zm_gamemodule_spawn_func))
|
|
{
|
|
self thread [[level.zm_gamemodule_spawn_func]]();
|
|
}
|
|
|
|
self thread player_spawn_protection();
|
|
if(!isDefined(self.lives))
|
|
{
|
|
self.lives = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function player_spawn_protection()
|
|
{
|
|
self endon("disconnect");
|
|
self zm_utility::increment_ignoreme();
|
|
x = 0;
|
|
while( x < 60 )
|
|
{
|
|
x++;
|
|
wait(.05);
|
|
}
|
|
self zm_utility::decrement_ignoreme();
|
|
}
|
|
|
|
function spawn_life_brush( origin, radius, height )
|
|
{
|
|
life_brush = spawn( "trigger_radius", origin, 0, radius, height );
|
|
life_brush.script_noteworthy = "life_brush";
|
|
|
|
return life_brush;
|
|
}
|
|
|
|
|
|
function in_life_brush()
|
|
{
|
|
life_brushes = getentarray( "life_brush", "script_noteworthy" );
|
|
|
|
if ( !IsDefined( life_brushes ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for ( i = 0; i < life_brushes.size; i++ )
|
|
{
|
|
|
|
if ( self IsTouching( life_brushes[i] ) )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
function spawn_kill_brush( origin, radius, height )
|
|
{
|
|
kill_brush = spawn( "trigger_radius", origin, 0, radius, height );
|
|
kill_brush.script_noteworthy = "kill_brush";
|
|
|
|
return kill_brush;
|
|
}
|
|
|
|
|
|
function in_kill_brush()
|
|
{
|
|
kill_brushes = getentarray( "kill_brush", "script_noteworthy" );
|
|
|
|
self.kill_brush = undefined;
|
|
|
|
if ( !IsDefined( kill_brushes ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for ( i = 0; i < kill_brushes.size; i++ )
|
|
{
|
|
|
|
if ( self IsTouching( kill_brushes[i] ) )
|
|
{
|
|
self.kill_brush = kill_brushes[i];
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
function in_enabled_playable_area()
|
|
{
|
|
zm_zonemgr::wait_zone_flags_updating();
|
|
|
|
playable_area = getentarray( "player_volume", "script_noteworthy" );
|
|
|
|
if( !IsDefined( playable_area ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for ( i = 0; i < playable_area.size; i++ )
|
|
{
|
|
if ( zm_zonemgr::zone_is_enabled( playable_area[i].targetname ) && self IsTouching( playable_area[i] ) )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
function get_player_out_of_playable_area_monitor_wait_time()
|
|
{
|
|
/#
|
|
if ( ( isdefined( level.check_kill_thread_every_frame ) && level.check_kill_thread_every_frame ) )
|
|
{
|
|
return 0.05;
|
|
}
|
|
#/
|
|
|
|
return 3;
|
|
}
|
|
|
|
|
|
function player_out_of_playable_area_monitor()
|
|
{
|
|
self notify( "stop_player_out_of_playable_area_monitor" );
|
|
self endon( "stop_player_out_of_playable_area_monitor" );
|
|
self endon( "disconnect" );
|
|
level endon( "end_game" );
|
|
|
|
while(!isDefined(self.characterindex))
|
|
{
|
|
wait(.05);
|
|
}
|
|
// load balancing
|
|
wait( (0.15 * self.characterindex) );
|
|
|
|
while ( true )
|
|
{
|
|
// skip over players in spectate, otherwise Sam keeps laughing every 3 seconds since their corpse is still invisibly in a kill area
|
|
if ( self.sessionstate == "spectator" )
|
|
{
|
|
wait( get_player_out_of_playable_area_monitor_wait_time() );
|
|
continue;
|
|
}
|
|
|
|
if(( isdefined( level.hostmigration_occured ) && level.hostmigration_occured ))
|
|
{
|
|
wait( get_player_out_of_playable_area_monitor_wait_time() );
|
|
continue;
|
|
}
|
|
|
|
if ( !self in_life_brush() && (self in_kill_brush() || !self in_enabled_playable_area() || ( isdefined(level.player_out_of_playable_area_override) && ( isdefined( self [[level.player_out_of_playable_area_override]]() ) && self [[level.player_out_of_playable_area_override]]() ) ) ) )
|
|
{
|
|
if ( !isdefined( level.player_out_of_playable_area_monitor_callback ) || self [[level.player_out_of_playable_area_monitor_callback]]() )
|
|
{
|
|
/#
|
|
if ( ( isdefined( level.kill_thread_test_mode ) && level.kill_thread_test_mode ) )
|
|
{
|
|
PrintTopRightln( "out of playable area: " + self.origin );
|
|
wait( get_player_out_of_playable_area_monitor_wait_time() );
|
|
continue;
|
|
}
|
|
|
|
if ( self isinmovemode( "ufo", "noclip" ) || ( isdefined( level.disable_kill_thread ) && level.disable_kill_thread ) || GetDvarInt( "zombie_cheat" ) > 0 )
|
|
{
|
|
wait( get_player_out_of_playable_area_monitor_wait_time() );
|
|
continue;
|
|
}
|
|
#/
|
|
|
|
//track the cheaters
|
|
self zm_stats::increment_map_cheat_stat( "cheat_out_of_playable" );
|
|
self zm_stats::increment_client_stat( "cheat_out_of_playable",false );
|
|
self zm_stats::increment_client_stat( "cheat_total",false );
|
|
|
|
self playlocalsound( level.zmb_laugh_alias );
|
|
|
|
wait( 0.5 );
|
|
|
|
if ( GetPlayers().size == 1 && level flag::get( "solo_game" ) && ( isdefined( self.waiting_to_revive ) && self.waiting_to_revive ) )
|
|
{
|
|
level notify( "end_game" );
|
|
}
|
|
else
|
|
{
|
|
self DisableInvulnerability();
|
|
self.lives = 0;
|
|
self dodamage( self.health + 1000, self.origin );
|
|
self.bleedout_time = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
wait( get_player_out_of_playable_area_monitor_wait_time() );
|
|
}
|
|
}
|
|
|
|
|
|
function get_player_too_many_weapons_monitor_wait_time()
|
|
{
|
|
return 3;
|
|
}
|
|
|
|
|
|
function player_too_many_weapons_monitor_takeaway_simultaneous( primary_weapons_to_take )
|
|
{
|
|
self endon( "player_too_many_weapons_monitor_takeaway_sequence_done" );
|
|
|
|
self util::waittill_any( "player_downed", "replace_weapon_powerup" );
|
|
|
|
for ( i = 0; i < primary_weapons_to_take.size; i++ )
|
|
{
|
|
self TakeWeapon( primary_weapons_to_take[i] );
|
|
}
|
|
|
|
self zm_score::player_reduce_points( "take_all" );
|
|
self zm_utility::give_start_weapon( false );
|
|
if ( !self laststand::player_is_in_laststand() )
|
|
{
|
|
self zm_utility::decrement_is_drinking();
|
|
}
|
|
else if ( level flag::get( "solo_game" ) )
|
|
{
|
|
self.score_lost_when_downed = 0;
|
|
}
|
|
|
|
self notify( "player_too_many_weapons_monitor_takeaway_sequence_done" );
|
|
}
|
|
|
|
|
|
function player_too_many_weapons_monitor_takeaway_sequence( primary_weapons_to_take )
|
|
{
|
|
self thread player_too_many_weapons_monitor_takeaway_simultaneous( primary_weapons_to_take );
|
|
|
|
self endon( "player_downed" );
|
|
self endon( "replace_weapon_powerup" );
|
|
|
|
self zm_utility::increment_is_drinking();
|
|
score_decrement = zm_utility::round_up_to_ten( int( self.score / (primary_weapons_to_take.size + 1) ) );
|
|
|
|
for ( i = 0; i < primary_weapons_to_take.size; i++ )
|
|
{
|
|
self playlocalsound( level.zmb_laugh_alias );
|
|
self SwitchToWeapon( primary_weapons_to_take[i] );
|
|
self zm_score::player_reduce_points( "take_specified", score_decrement );
|
|
wait( 3 );
|
|
|
|
self TakeWeapon( primary_weapons_to_take[i] );
|
|
}
|
|
|
|
self playlocalsound( level.zmb_laugh_alias );
|
|
self zm_score::player_reduce_points( "take_all" );
|
|
wait( 1 );
|
|
self zm_utility::give_start_weapon( true );
|
|
self zm_utility::decrement_is_drinking();
|
|
|
|
self notify( "player_too_many_weapons_monitor_takeaway_sequence_done" );
|
|
}
|
|
|
|
function player_too_many_weapons_monitor()
|
|
{
|
|
self notify( "stop_player_too_many_weapons_monitor" );
|
|
self endon( "stop_player_too_many_weapons_monitor" );
|
|
self endon( "disconnect" );
|
|
level endon( "end_game" );
|
|
|
|
// load balancing
|
|
scalar = self.characterindex;
|
|
|
|
if ( !isdefined( scalar ) )
|
|
{
|
|
scalar = self GetEntityNumber();
|
|
}
|
|
|
|
wait( (0.15 * scalar) );
|
|
|
|
while ( true )
|
|
{
|
|
if ( self zm_utility::has_powerup_weapon() || self laststand::player_is_in_laststand() || self.sessionstate == "spectator" || isdefined( self.laststandpistol ) )
|
|
{
|
|
wait( get_player_too_many_weapons_monitor_wait_time() );
|
|
continue;
|
|
}
|
|
|
|
/#
|
|
if ( GetDvarInt( "zombie_cheat" ) > 0 )
|
|
{
|
|
wait( get_player_too_many_weapons_monitor_wait_time() );
|
|
continue;
|
|
}
|
|
#/
|
|
|
|
weapon_limit = zm_utility::get_player_weapon_limit( self );
|
|
|
|
primaryWeapons = self GetWeaponsListPrimaries();
|
|
|
|
if ( primaryWeapons.size > weapon_limit )
|
|
{
|
|
self zm_weapons::take_fallback_weapon();
|
|
primaryWeapons = self GetWeaponsListPrimaries();
|
|
}
|
|
|
|
primary_weapons_to_take = [];
|
|
for ( i = 0; i < primaryWeapons.size; i++ )
|
|
{
|
|
if ( zm_weapons::is_weapon_included( primaryWeapons[i] ) || zm_weapons::is_weapon_upgraded( primaryWeapons[i] ) )
|
|
{
|
|
primary_weapons_to_take[primary_weapons_to_take.size] = primaryWeapons[i];
|
|
}
|
|
}
|
|
|
|
if ( primary_weapons_to_take.size > weapon_limit )
|
|
{
|
|
if ( !isdefined( level.player_too_many_weapons_monitor_callback ) || self [[level.player_too_many_weapons_monitor_callback]]( primary_weapons_to_take ) )
|
|
{
|
|
//track the cheaters
|
|
self zm_stats::increment_map_cheat_stat( "cheat_too_many_weapons" );
|
|
self zm_stats::increment_client_stat( "cheat_too_many_weapons",false );
|
|
self zm_stats::increment_client_stat( "cheat_total",false );
|
|
|
|
|
|
self thread player_too_many_weapons_monitor_takeaway_sequence( primary_weapons_to_take );
|
|
self waittill( "player_too_many_weapons_monitor_takeaway_sequence_done" );
|
|
}
|
|
}
|
|
|
|
wait( get_player_too_many_weapons_monitor_wait_time() );
|
|
}
|
|
}
|
|
|
|
|
|
function player_monitor_travel_dist()
|
|
{
|
|
self endon("disconnect");
|
|
self notify("stop_player_monitor_travel_dist");
|
|
self endon("stop_player_monitor_travel_dist");
|
|
|
|
prevpos = self.origin;
|
|
while(1)
|
|
{
|
|
wait .1;
|
|
|
|
self.pers["distance_traveled"] += distance( self.origin, prevpos ) ;
|
|
prevpos = self.origin;
|
|
}
|
|
}
|
|
|
|
function player_monitor_time_played()
|
|
{
|
|
self endon( "disconnect" );
|
|
self notify("stop_player_monitor_time_played");
|
|
self endon("stop_player_monitor_time_played");
|
|
|
|
level flag::wait_till( "start_zombie_round_logic" );
|
|
|
|
for ( ;; )
|
|
{
|
|
wait ( 1.0 );
|
|
zm_stats::increment_client_stat( "time_played_total" );
|
|
}
|
|
}
|
|
|
|
function player_grenade_multiattack_bookmark_watcher( grenade )
|
|
{
|
|
self endon( "disconnect" );
|
|
|
|
waittillframeend;
|
|
|
|
if ( !IsDefined( grenade ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
inflictorEntNum = grenade getEntityNumber();
|
|
inflictorEntType = grenade getEntityType();
|
|
inflictorBirthTime = 0;
|
|
if ( isDefined( grenade.birthTime ) )
|
|
inflictorBirthTime = grenade.birthTime;
|
|
|
|
ret_val = grenade util::waittill_any_ex( 15, "explode", "death", self, "disconnect" );
|
|
|
|
if ( !IsDefined( self ) || (IsDefined( ret_val ) && "timeout" == ret_val) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self.grenade_multiattack_count = 0;
|
|
self.grenade_multiattack_ent = undefined;
|
|
self.grenade_multikill_count = 0; // Black Ops 3 - TU1 Fix; track multikill count in addition to multiattack, for the Five-for-One Challenge
|
|
|
|
waittillframeend;
|
|
|
|
if ( !IsDefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
count = level.grenade_multiattack_bookmark_count;
|
|
if ( ( isdefined( grenade.grenade_multiattack_bookmark_count ) && grenade.grenade_multiattack_bookmark_count ) )
|
|
{
|
|
count = grenade.grenade_multiattack_bookmark_count;
|
|
}
|
|
|
|
bookmark_string = "zm_player_grenade_multiattack";
|
|
if ( ( isdefined( grenade.use_grenade_special_long_bookmark ) && grenade.use_grenade_special_long_bookmark ) )
|
|
{
|
|
bookmark_string = "zm_player_grenade_special_long";
|
|
}
|
|
else if ( ( isdefined( grenade.use_grenade_special_bookmark ) && grenade.use_grenade_special_bookmark ) )
|
|
{
|
|
bookmark_string = "zm_player_grenade_special";
|
|
}
|
|
|
|
if ( count <= self.grenade_multiattack_count && IsDefined( self.grenade_multiattack_ent ) )
|
|
{
|
|
addDemoBookmark( bookmark_string, gettime(), self GetEntityNumber(), 255, 0, inflictorEntNum, inflictorEntType, inflictorBirthTime, false, self.grenade_multiattack_ent GetEntityNumber() );
|
|
}
|
|
|
|
if ( 5 <= self.grenade_multikill_count ) // Black Ops 3 - TU1 Fix; track multikill count in addition to multiattack, for the Five-for-One Challenge
|
|
{
|
|
self zm_stats::increment_challenge_stat( "ZOMBIE_HUNTER_EXPLOSION_MULTIKILL" );
|
|
}
|
|
|
|
self.grenade_multiattack_count = 0;
|
|
self.grenade_multikill_count = 0; // Black Ops 3 - TU1 Fix; track multikill count in addition to multiattack, for the Five-for-One Challenge
|
|
}
|
|
|
|
|
|
function player_grenade_watcher()
|
|
{
|
|
self endon( "disconnect" );
|
|
|
|
self notify("stop_player_grenade_watcher");
|
|
self endon("stop_player_grenade_watcher");
|
|
|
|
self.grenade_multiattack_count = 0;
|
|
self.grenade_multikill_count = 0; //this was added to "player_grenade_multiattack_bookmark_watcher" for TU1, but not added here, which was causing a SRE.
|
|
|
|
while ( 1 )
|
|
{
|
|
self waittill( "grenade_fire", grenade, weapon );
|
|
|
|
if( isdefined( grenade ) && isalive( grenade ) )
|
|
{
|
|
grenade.team = self.team;
|
|
}
|
|
|
|
self thread player_grenade_multiattack_bookmark_watcher( grenade );
|
|
|
|
if ( isdefined( level.grenade_watcher ) )
|
|
{
|
|
self [[ level.grenade_watcher ]]( grenade, weapon );
|
|
}
|
|
}
|
|
}
|
|
|
|
function player_prevent_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime )
|
|
{
|
|
if( !isdefined( eInflictor ) || !isdefined( eAttacker ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( eInflictor == self || eAttacker == self )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( isdefined( eInflictor ) && isdefined( eInflictor.team ) )
|
|
{
|
|
if (!( isdefined( eInflictor.damage_own_team ) && eInflictor.damage_own_team ))
|
|
if ( eInflictor.team == self.team )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Keep track of players going down and getting revived
|
|
function player_revive_monitor()
|
|
{
|
|
self endon( "disconnect" );
|
|
self notify("stop_player_revive_monitor");
|
|
self endon("stop_player_revive_monitor");
|
|
|
|
while (1)
|
|
{
|
|
self waittill( "player_revived", reviver );
|
|
|
|
self playsoundtoplayer( "zmb_character_revived", self );
|
|
|
|
if(( isdefined( level.isresetting_grief ) && level.isresetting_grief ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//self laststand_giveback_player_perks();
|
|
|
|
if ( IsDefined(reviver) )
|
|
{
|
|
if( reviver != self )
|
|
{
|
|
if( math::cointoss() )
|
|
self zm_audio::create_and_play_dialog( "general", "revive_up" );
|
|
else
|
|
reviver zm_audio::create_and_play_dialog( "general", "revive_support" );
|
|
}
|
|
else
|
|
{
|
|
self zm_audio::create_and_play_dialog( "general", "revive_up" );
|
|
}
|
|
|
|
//reviver maps\_zombiemode_rank::giveRankXp( "revive" );
|
|
//maps\_zombiemode_challenges::doMissionCallback( "zm_revive", reviver );
|
|
|
|
// Check to see how much money you lost from being down.
|
|
points = self.score_lost_when_downed;
|
|
|
|
if ( !isdefined( points ) )
|
|
{
|
|
points = 0;
|
|
}
|
|
|
|
/# println( "ZM >> LAST STAND - points = " + points); #/
|
|
|
|
reviver zm_score::player_add_points( "reviver", points );
|
|
self.score_lost_when_downed = 0;
|
|
|
|
if ( IsPlayer( reviver ) && reviver != self )
|
|
{
|
|
reviver zm_stats::increment_challenge_stat( "SURVIVALIST_REVIVE" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// self = a player
|
|
// If the player has just 1 perk, they wil always get it back
|
|
// If the player has more than 1 perk, they will lose a single perk
|
|
function laststand_giveback_player_perks()
|
|
{
|
|
if ( IsDefined( self.laststand_perks ) )
|
|
{
|
|
// Calculate a lost perk index
|
|
lost_perk_index = int( -1 );
|
|
if( self.laststand_perks.size > 1 )
|
|
{
|
|
lost_perk_index = RandomInt( self.laststand_perks.size-1 );
|
|
}
|
|
|
|
// Give the player back their perks
|
|
for ( i=0; i<self.laststand_perks.size; i++ )
|
|
{
|
|
if ( self HasPerk( self.laststand_perks[i] ) )
|
|
{
|
|
continue;
|
|
}
|
|
if( i == lost_perk_index )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
zm_perks::give_perk( self.laststand_perks[i] );
|
|
}
|
|
}
|
|
}
|
|
|
|
function remote_revive_watch()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "player_revived" );
|
|
|
|
keep_checking = true;
|
|
while( keep_checking )
|
|
{
|
|
self waittill( "remote_revive", reviver );
|
|
|
|
//Check the remote reviver is on the same team
|
|
if( reviver.team == self.team )
|
|
keep_checking = false;
|
|
}
|
|
|
|
self zm_laststand::remote_revive( reviver );
|
|
}
|
|
|
|
function player_laststand( eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration )
|
|
{
|
|
/# println( "ZM >> LAST STAND - player_laststand called" ); #/
|
|
|
|
b_alt_visionset = false;
|
|
|
|
self AllowJump(false);
|
|
|
|
currWeapon = self GetCurrentWeapon();
|
|
|
|
self AddWeaponStat( currWeapon, "deathsDuringUse", 1 );
|
|
|
|
// Grab the perks if we have the player persistent ability "perk lose"
|
|
if( ( isdefined( self.pers_upgrades_awarded["perk_lose"] ) && self.pers_upgrades_awarded["perk_lose"] ) )
|
|
{
|
|
self zm_pers_upgrades_functions::pers_upgrade_perk_lose_save();
|
|
}
|
|
|
|
players = GetPlayers();
|
|
if ( players.size == 1 && level flag::get( "solo_game" ) )
|
|
{
|
|
if ( self.lives > 0 && self HasPerk("specialty_quickrevive") )
|
|
{
|
|
self thread wait_and_revive();
|
|
}
|
|
}
|
|
|
|
self zm_utility::clear_is_drinking();
|
|
|
|
self thread remote_revive_watch();
|
|
|
|
self zm_score::player_downed_penalty();
|
|
|
|
// Turns out we need to do this after all, but we don't want to change _laststand.gsc postship, so I'm doing it here manually instead
|
|
self DisableOffhandWeapons();
|
|
|
|
self thread last_stand_grenade_save_and_return();
|
|
|
|
if( sMeansOfDeath != "MOD_SUICIDE" && sMeansOfDeath != "MOD_FALLING" )
|
|
{
|
|
if( !( isdefined( self.intermission ) && self.intermission ) )
|
|
self zm_audio::create_and_play_dialog( "general", "revive_down" );
|
|
else
|
|
{
|
|
if(isDefined(level.custom_player_death_vo_func) && !self [[level.custom_player_death_vo_func]]() )
|
|
{
|
|
self zm_audio::create_and_play_dialog( "general", "exert_death" );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( IsDefined( level._zombie_minigun_powerup_last_stand_func ) )
|
|
{
|
|
self thread [[level._zombie_minigun_powerup_last_stand_func]]();
|
|
}
|
|
|
|
if( IsDefined( level._zombie_tesla_powerup_last_stand_func ) )
|
|
{
|
|
self thread [[level._zombie_tesla_powerup_last_stand_func]]();
|
|
}
|
|
|
|
if ( self HasPerk( "specialty_electriccherry" ) )
|
|
{
|
|
b_alt_visionset = true;
|
|
|
|
if ( IsDefined( level.custom_laststand_func ) )
|
|
{
|
|
self thread [[ level.custom_laststand_func ]]();
|
|
}
|
|
}
|
|
|
|
if( IsDefined( self.intermission ) && self.intermission )
|
|
{
|
|
//maps\_zombiemode_challenges::doMissionCallback( "playerDied", self );
|
|
|
|
wait(.5);
|
|
self stopsounds();
|
|
|
|
level waittill( "forever" );
|
|
}
|
|
|
|
if ( !( b_alt_visionset ) )
|
|
{
|
|
visionset_mgr::activate( "visionset", "zombie_last_stand", self, 1 );
|
|
}
|
|
}
|
|
|
|
|
|
function failsafe_revive_give_back_weapons(excluded_player)
|
|
{
|
|
for ( i = 0; i < 10; i++ )
|
|
{
|
|
{wait(.05);};
|
|
|
|
players = GetPlayers();
|
|
foreach(player in players )
|
|
{
|
|
if (player == excluded_player|| !isdefined( player.reviveProgressBar ) || player zm_laststand::is_reviving_any() )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// he's not reviving anyone but he still has revive stuff up, clean it all up
|
|
/#
|
|
iprintlnbold( "FAILSAFE CLEANING UP REVIVE HUD AND GUN" );
|
|
#/
|
|
// pass in "none" since we have no idea what the weapon they should be showing is
|
|
player zm_laststand::revive_give_back_weapons( level.weaponNone );
|
|
|
|
if ( isdefined( player.reviveProgressBar ) )
|
|
{
|
|
player.reviveProgressBar hud::destroyElem();
|
|
}
|
|
|
|
if ( isdefined( player.reviveTextHud ) )
|
|
{
|
|
player.reviveTextHud destroy();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function set_intermission_point()
|
|
{
|
|
points =struct::get_array( "intermission", "targetname" );
|
|
|
|
if( points.size < 1 )
|
|
{
|
|
return;
|
|
}
|
|
points = array::randomize( points );
|
|
|
|
point = points[0];
|
|
|
|
SetDemoIntermissionPoint( point.origin, point.angles );
|
|
}
|
|
|
|
|
|
function spawnSpectator()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "spawned_spectator" );
|
|
self notify( "spawned" );
|
|
self notify( "end_respawn" );
|
|
|
|
if( level.intermission )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( IsDefined( level.no_spectator ) && level.no_spectator )
|
|
{
|
|
wait( 3 );
|
|
ExitLevel();
|
|
}
|
|
|
|
// The check_for_level_end looks for this
|
|
self.is_zombie = true;
|
|
|
|
//failsafe against losing viewarms due to the thread returning them getting an endon from "zombified"
|
|
level thread failsafe_revive_give_back_weapons(self);
|
|
|
|
// Remove all reviving abilities
|
|
self notify ( "zombified" );
|
|
|
|
if( isdefined( self.revivetrigger ) )
|
|
{
|
|
self.revivetrigger delete();
|
|
self.revivetrigger = undefined;
|
|
}
|
|
|
|
self.zombification_time = GetTime(); //set time when player died
|
|
|
|
resetTimeout();
|
|
|
|
// Stop shellshock and rumble
|
|
self StopShellshock();
|
|
self StopRumble( "damage_heavy" );
|
|
|
|
self.sessionstate = "spectator";
|
|
self.spectatorclient = -1;
|
|
|
|
self.maxhealth = self.health;
|
|
self.shellshocked = false;
|
|
self.inWater = false;
|
|
self.friendlydamage = undefined;
|
|
self.hasSpawned = true;
|
|
self.spawnTime = GetTime();
|
|
self.afk = false;
|
|
|
|
/# println( "*************************Zombie Spectator***" ); #/
|
|
self detachAll();
|
|
|
|
if( isdefined( level.custom_spectate_permissions ) )
|
|
{
|
|
self [[level.custom_spectate_permissions]]();
|
|
}
|
|
else
|
|
{
|
|
self setSpectatePermissions( true );
|
|
}
|
|
self thread spectator_thread();
|
|
|
|
self Spawn( self.origin, self.angles );
|
|
self notify( "spawned_spectator" );
|
|
}
|
|
|
|
function setSpectatePermissions( isOn )
|
|
{
|
|
self AllowSpectateTeam( "allies", isOn && self.team == "allies" );
|
|
self AllowSpectateTeam( "axis", isOn && self.team == "axis" );
|
|
self AllowSpectateTeam( "freelook", false );
|
|
self AllowSpectateTeam( "none", false );
|
|
}
|
|
|
|
function spectator_thread()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "spawned_player" );
|
|
|
|
/* we are not currently supporting the shared screen tech
|
|
if( self IsSplitScreen() )
|
|
{
|
|
last_alive = undefined;
|
|
players = GetPlayers();
|
|
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
if( !players[i].is_zombie )
|
|
{
|
|
last_alive = players[i];
|
|
}
|
|
}
|
|
|
|
share_screen( last_alive, true );
|
|
|
|
return;
|
|
}
|
|
*/
|
|
|
|
// self thread spectator_toggle_3rd_person();
|
|
}
|
|
|
|
function spectator_toggle_3rd_person()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "spawned_player" );
|
|
|
|
third_person = true;
|
|
self set_third_person( true );
|
|
}
|
|
|
|
|
|
function set_third_person( value )
|
|
{
|
|
if( value )
|
|
{
|
|
self SetClientThirdPerson( 1 );
|
|
self SetClientThirdPersonAngle( 354 );
|
|
|
|
self setDepthOfField( 0, 128, 512, 4000, 6, 1.8 );
|
|
}
|
|
else
|
|
{
|
|
self SetClientThirdPerson( 0 );
|
|
self SetClientThirdPersonAngle( 0 );
|
|
|
|
self setDepthOfField( 0, 0, 512, 4000, 4, 0 );
|
|
}
|
|
self resetFov();
|
|
}
|
|
|
|
function last_stand_revive()
|
|
{
|
|
level endon( "between_round_over" );
|
|
|
|
players = GetPlayers();
|
|
|
|
|
|
//If everyone is in last stand or spectate then revive all
|
|
laststand_count = 0;
|
|
foreach(player in players)
|
|
{
|
|
if( !zm_utility::is_player_valid( player ) )
|
|
{
|
|
laststand_count ++;
|
|
}
|
|
}
|
|
|
|
if( laststand_count == players.size )
|
|
{
|
|
for ( i = 0; i < players.size; i++ )
|
|
{
|
|
if ( players[i] laststand::player_is_in_laststand() && players[i].revivetrigger.beingRevived == 0 )
|
|
{
|
|
players[i] zm_laststand::auto_revive( players[i] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ww: arrange the last stand pistols so when it come time to choose which one they are inited
|
|
function last_stand_pistol_rank_init()
|
|
{
|
|
level.pistol_values = [];
|
|
|
|
// ww: in a solo game the ranking of the pistols is a bit different based on the upgraded 1911 swap
|
|
// any pistol ranked level.pistol_value_solo_replace_below or lower will be ignored and the player will be given the upgraded 1911
|
|
level.pistol_values[ level.pistol_values.size ] = level.default_laststandpistol;
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "pistol_burst" );
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "pistol_fullauto" );
|
|
level.pistol_value_solo_replace_below = level.pistol_values.size-1; // EO: anything scoring lower than this should be replaced
|
|
level.pistol_values[ level.pistol_values.size ] = level.default_solo_laststandpistol;
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "pistol_burst_upgraded" );
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "pistol_fullauto_upgraded" );
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "ray_gun" );
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "raygun_mark2" );
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "ray_gun_upgraded" );
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "raygun_mark2_upgraded" );
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "raygun_mark3" );
|
|
level.pistol_values[ level.pistol_values.size ] = GetWeapon( "raygun_mark3_upgraded" );
|
|
}
|
|
|
|
function last_stand_pistol_swap()
|
|
{
|
|
if ( self zm_utility::has_powerup_weapon() )
|
|
{
|
|
// this will force the laststand module to switch us to any primary weapon, since we will no longer have this after revive
|
|
self.lastActiveWeapon = level.weaponNone;
|
|
}
|
|
|
|
// PORTIZ: chance to override the player's last stand pistol, but only if the override is stronger than the current one
|
|
if ( isdefined( self.w_min_last_stand_pistol_override ) )
|
|
{
|
|
self last_stand_minimum_pistol_override();
|
|
}
|
|
|
|
if ( !self HasWeapon( self.laststandpistol ) )
|
|
{
|
|
self GiveWeapon( self.laststandpistol );
|
|
}
|
|
ammoclip = self.laststandpistol.clipSize;
|
|
doubleclip = ammoclip * 2;
|
|
|
|
if( ( isdefined( self._special_solo_pistol_swap ) && self._special_solo_pistol_swap ) || (self.laststandpistol == level.default_solo_laststandpistol && !self.hadpistol) )
|
|
{
|
|
self._special_solo_pistol_swap = 0;
|
|
self.hadpistol = false;
|
|
self SetWeaponAmmoStock( self.laststandpistol, doubleclip );
|
|
}
|
|
else if( level flag::get("solo_game") && self.laststandpistol == level.default_solo_laststandpistol )
|
|
{
|
|
self SetWeaponAmmoStock( self.laststandpistol, doubleclip );
|
|
}
|
|
else if ( self.laststandpistol == level.default_laststandpistol )
|
|
{
|
|
self SetWeaponAmmoStock( self.laststandpistol, doubleclip );
|
|
}
|
|
else if ( !isdefined( self.stored_weapon_info ) || !isdefined( self.stored_weapon_info[ self.laststandpistol ] ) )
|
|
{
|
|
self SetWeaponAmmoStock( self.laststandpistol, doubleclip ); // PORTIZ: in the case that we awarded a temporary last stand weapon, just set the stock and skip the ammo tracking
|
|
}
|
|
else if ( self.laststandpistol.name == "ray_gun" || self.laststandpistol.name == "ray_gun_upgraded" )
|
|
{
|
|
if ( self.stored_weapon_info[ self.laststandpistol ].total_amt >= ammoclip )
|
|
{
|
|
self SetWeaponAmmoClip( self.laststandpistol, ammoclip );
|
|
self.stored_weapon_info[ self.laststandpistol ].given_amt = ammoclip;
|
|
}
|
|
else
|
|
{
|
|
self SetWeaponAmmoClip( self.laststandpistol, self.stored_weapon_info[ self.laststandpistol ].total_amt );
|
|
self.stored_weapon_info[ self.laststandpistol ].given_amt = self.stored_weapon_info[ self.laststandpistol ].total_amt;
|
|
}
|
|
self SetWeaponAmmoStock( self.laststandpistol, 0 );
|
|
}
|
|
else
|
|
{
|
|
if ( self.stored_weapon_info[ self.laststandpistol ].stock_amt >= doubleclip )
|
|
{
|
|
self SetWeaponAmmoStock( self.laststandpistol, doubleclip );
|
|
self.stored_weapon_info[ self.laststandpistol ].given_amt = doubleclip + self.stored_weapon_info[ self.laststandpistol ].clip_amt + self.stored_weapon_info[ self.laststandpistol ].left_clip_amt;
|
|
}
|
|
else
|
|
{
|
|
self SetWeaponAmmoStock( self.laststandpistol, self.stored_weapon_info[ self.laststandpistol ].stock_amt );
|
|
self.stored_weapon_info[ self.laststandpistol ].given_amt = self.stored_weapon_info[ self.laststandpistol ].total_amt;
|
|
}
|
|
}
|
|
|
|
self SwitchToWeapon( self.laststandpistol );
|
|
}
|
|
|
|
// PORTIZ: this runs if self.w_min_last_stand_pistol_override is defined, and just before the player is given his last stand pistol.
|
|
function last_stand_minimum_pistol_override()
|
|
{
|
|
for( i = 0; i < level.pistol_values.size; i++ )
|
|
{
|
|
if( level.pistol_values[i] == self.w_min_last_stand_pistol_override )
|
|
{
|
|
n_min_last_stand_pistol_value = i; // find the value corresponding to our override weapon
|
|
break;
|
|
}
|
|
}
|
|
|
|
for( k = 0; k < level.pistol_values.size; k++ )
|
|
{
|
|
if( level.pistol_values[k] == self.laststandpistol )
|
|
{
|
|
n_default_last_stand_pistol_value = k; // find the value corresponding to our default last stand weapon
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( n_min_last_stand_pistol_value > n_default_last_stand_pistol_value )
|
|
{
|
|
self.hadpistol = false;
|
|
self.laststandpistol = self.w_min_last_stand_pistol_override;
|
|
}
|
|
}
|
|
|
|
// ww: make sure the player has the best pistol when they go in to last stand
|
|
function last_stand_best_pistol()
|
|
{
|
|
pistol_array = [];
|
|
|
|
current_weapons = self GetWeaponsListPrimaries();
|
|
|
|
for( i = 0; i < current_weapons.size; i++ )
|
|
{
|
|
// make sure the weapon is a pistol
|
|
wclass = current_weapons[i].weapClass;
|
|
if ( current_weapons[i].isBallisticKnife )
|
|
{
|
|
wclass = "knife";
|
|
}
|
|
|
|
if ( wclass == "pistol" || wclass == "pistolspread" || wclass == "pistol spread" )
|
|
{
|
|
if ( (current_weapons[i] != level.default_solo_laststandpistol && !level flag::get("solo_game") ) || (!level flag::get("solo_game") && current_weapons[i] != level.default_solo_laststandpistol ))
|
|
{
|
|
if( (current_weapons[i] != self.laststandpistol) || (self.laststandpistol != level.default_laststandpistol) )
|
|
{
|
|
if ( self GetAmmoCount( current_weapons[i] ) <= 0 )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
pistol_array_index = pistol_array.size; // set up the spot in the array
|
|
pistol_array[ pistol_array_index ] = SpawnStruct(); // struct to store info on
|
|
|
|
pistol_array[ pistol_array_index ].weapon = current_weapons[i];
|
|
pistol_array[ pistol_array_index ].value = 0; // add a value in case a new weapon is introduced that hasn't been set up in level.pistol_values
|
|
|
|
// compare the current weapon to the level.pistol_values to see what the value is
|
|
for( j = 0; j < level.pistol_values.size; j++ )
|
|
{
|
|
if( level.pistol_values[j] == current_weapons[i].rootWeapon )
|
|
{
|
|
pistol_array[ pistol_array_index ].value = j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
self.laststandpistol = last_stand_compare_pistols( pistol_array );
|
|
}
|
|
|
|
// ww: compares the array passed in for the highest valued pistol
|
|
function last_stand_compare_pistols( struct_array )
|
|
{
|
|
if( !IsArray( struct_array ) || struct_array.size <= 0 )
|
|
{
|
|
self.hadpistol = false;
|
|
|
|
//array will be empty if the pistol had no ammo...so lets see if the player had the pistol
|
|
if(isDefined(self.stored_weapon_info))
|
|
{
|
|
stored_weapon_info = GetArrayKeys( self.stored_weapon_info );
|
|
for( j = 0; j < stored_weapon_info.size; j++ )
|
|
{
|
|
if( stored_weapon_info[ j ].rootWeapon == level.laststandpistol)
|
|
{
|
|
self.hadpistol = true;
|
|
return stored_weapon_info[ j ];
|
|
}
|
|
}
|
|
}
|
|
|
|
return level.laststandpistol; // nothing in the array then give the level last stand pistol
|
|
}
|
|
|
|
highest_score_pistol = struct_array[0]; // first time through give the first one to the highest score
|
|
|
|
for( i = 1; i < struct_array.size; i++ )
|
|
{
|
|
if( struct_array[i].value > highest_score_pistol.value )
|
|
{
|
|
highest_score_pistol = struct_array[i];
|
|
}
|
|
}
|
|
|
|
if( level flag::get( "solo_game" ) )
|
|
{
|
|
self._special_solo_pistol_swap = 0; // ww: this way the weapon knows to pack texture when given
|
|
if( highest_score_pistol.value <= level.pistol_value_solo_replace_below )
|
|
{
|
|
self.hadpistol = false;
|
|
self._special_solo_pistol_swap = 1;
|
|
|
|
if ( ( isdefined( level.force_solo_quick_revive ) && level.force_solo_quick_revive ) && ( !self HasPerk( "specialty_quickrevive" ) ) )
|
|
{
|
|
return highest_score_pistol.weapon; // ar: gun won't be replaced
|
|
}
|
|
else
|
|
{
|
|
return level.laststandpistol; // ww: if it scores too low the player gets the 1911 upgraded
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return highest_score_pistol.weapon; // ww: gun is high in ranking and won't be replaced
|
|
}
|
|
}
|
|
else // ww: happens when not in solo
|
|
{
|
|
return highest_score_pistol.weapon;
|
|
}
|
|
|
|
}
|
|
|
|
// ww: override function for saving player pistol ammo count
|
|
function last_stand_save_pistol_ammo()
|
|
{
|
|
weapon_inventory = self GetWeaponsList( true );
|
|
self.stored_weapon_info = [];
|
|
|
|
for( i = 0; i < weapon_inventory.size; i++ )
|
|
{
|
|
weapon = weapon_inventory[i];
|
|
|
|
wclass = weapon.weapClass;
|
|
if ( weapon.isBallisticKnife )
|
|
{
|
|
wclass = "knife";
|
|
}
|
|
|
|
if ( wclass == "pistol" || wclass == "pistolspread" || wclass == "pistol spread" )
|
|
{
|
|
self.stored_weapon_info[ weapon ] = SpawnStruct();
|
|
self.stored_weapon_info[ weapon ].clip_amt = self GetWeaponAmmoClip( weapon );
|
|
self.stored_weapon_info[ weapon ].left_clip_amt = 0;
|
|
dual_wield_weapon = weapon.dualWieldWeapon;
|
|
if ( level.weaponNone != dual_wield_weapon )
|
|
{
|
|
self.stored_weapon_info[ weapon ].left_clip_amt = self GetWeaponAmmoClip( dual_wield_weapon );
|
|
}
|
|
self.stored_weapon_info[ weapon ].stock_amt = self GetWeaponAmmoStock( weapon );
|
|
self.stored_weapon_info[ weapon ].total_amt = self.stored_weapon_info[ weapon ].clip_amt + self.stored_weapon_info[ weapon ].left_clip_amt + self.stored_weapon_info[ weapon ].stock_amt;
|
|
self.stored_weapon_info[ weapon ].given_amt = 0;
|
|
}
|
|
}
|
|
|
|
self last_stand_best_pistol();
|
|
}
|
|
|
|
// ww: override to restore the player's pistol ammo after being picked up
|
|
function last_stand_restore_pistol_ammo()
|
|
{
|
|
self.weapon_taken_by_losing_specialty_additionalprimaryweapon = level.weaponNone;
|
|
|
|
if ( !IsDefined( self.stored_weapon_info ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
weapon_inventory = self GetWeaponsList( true );
|
|
weapon_to_restore = GetArrayKeys( self.stored_weapon_info );
|
|
|
|
for( i = 0; i < weapon_inventory.size; i++ )
|
|
{
|
|
weapon = weapon_inventory[i];
|
|
|
|
if ( weapon != self.laststandpistol )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// for this loop, weapon == self.laststandpistol
|
|
for( j = 0; j < weapon_to_restore.size; j++ )
|
|
{
|
|
if ( weapon == weapon_to_restore[j] )
|
|
{
|
|
dual_wield_weapon = weapon_to_restore[j].dualWieldWeapon;
|
|
if ( weapon != level.default_laststandpistol )
|
|
{
|
|
last_clip = self GetWeaponAmmoClip( weapon );
|
|
last_left_clip = 0;
|
|
if ( level.weaponNone != dual_wield_weapon )
|
|
{
|
|
last_left_clip = self GetWeaponAmmoClip( dual_wield_weapon );
|
|
}
|
|
last_stock = self GetWeaponAmmoStock( weapon );
|
|
last_total = last_clip + last_left_clip + last_stock;
|
|
|
|
used_amt = self.stored_weapon_info[ weapon ].given_amt - last_total;
|
|
|
|
if ( used_amt >= self.stored_weapon_info[ weapon ].stock_amt )
|
|
{
|
|
used_amt -= self.stored_weapon_info[ weapon ].stock_amt;
|
|
self.stored_weapon_info[ weapon ].stock_amt = 0;
|
|
|
|
self.stored_weapon_info[ weapon ].clip_amt -= used_amt;
|
|
if ( self.stored_weapon_info[ weapon ].clip_amt < 0 )
|
|
{
|
|
self.stored_weapon_info[ weapon ].clip_amt = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
new_stock_amt = self.stored_weapon_info[ weapon ].stock_amt - used_amt;
|
|
if ( new_stock_amt < self.stored_weapon_info[ weapon ].stock_amt )
|
|
{
|
|
self.stored_weapon_info[ weapon ].stock_amt = new_stock_amt;
|
|
}
|
|
}
|
|
}
|
|
|
|
self SetWeaponAmmoClip( weapon, self.stored_weapon_info[weapon].clip_amt );
|
|
if ( level.weaponNone != dual_wield_weapon )
|
|
{
|
|
self SetWeaponAmmoClip( dual_wield_weapon, self.stored_weapon_info[weapon].left_clip_amt );
|
|
}
|
|
self SetWeaponAmmoStock( weapon, self.stored_weapon_info[weapon].stock_amt );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function last_stand_take_thrown_grenade()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "bled_out" );
|
|
self endon( "player_revived" );
|
|
|
|
self waittill ( "grenade_fire", grenade, weapon );
|
|
|
|
if ( isdefined(self.lsgsar_lethal) && weapon == self.lsgsar_lethal )
|
|
{
|
|
self.lsgsar_lethal_nade_amt--;
|
|
}
|
|
|
|
if ( isdefined(self.lsgsar_tactical) && weapon == self.lsgsar_tactical )
|
|
{
|
|
self.lsgsar_tactical_nade_amt--;
|
|
}
|
|
}
|
|
|
|
// ww: zeros out the player's grenades until they revive
|
|
function last_stand_grenade_save_and_return()
|
|
{
|
|
if(( isdefined( level.isresetting_grief ) && level.isresetting_grief )) //don't do this for Grief when resetting the round
|
|
{
|
|
return;
|
|
}
|
|
self endon( "disconnect" );
|
|
self endon ("bled_out");
|
|
|
|
self.lsgsar_lethal_nade_amt = 0;
|
|
self.lsgsar_has_lethal_nade = false;
|
|
self.lsgsar_tactical_nade_amt = 0;
|
|
self.lsgsar_has_tactical_nade = false;
|
|
self.lsgsar_lethal = undefined;
|
|
self.lsgsar_tactical = undefined;
|
|
|
|
if (self IsThrowingGrenade())
|
|
{
|
|
self thread last_stand_take_thrown_grenade();
|
|
}
|
|
|
|
weapon = self zm_utility::get_player_lethal_grenade();
|
|
if ( weapon != level.weaponNone )
|
|
{
|
|
self.lsgsar_has_lethal_nade = true;
|
|
self.lsgsar_lethal = weapon;
|
|
self.lsgsar_lethal_nade_amt = self GetWeaponAmmoClip( weapon );
|
|
self SetWeaponAmmoClip( weapon, 0 );
|
|
self TakeWeapon( weapon );
|
|
}
|
|
|
|
weapon = self zm_utility::get_player_tactical_grenade();
|
|
if ( weapon != level.weaponNone )
|
|
{
|
|
self.lsgsar_has_tactical_nade = true;
|
|
self.lsgsar_tactical = weapon;
|
|
self.lsgsar_tactical_nade_amt = self GetWeaponAmmoClip( weapon );
|
|
self SetWeaponAmmoClip( weapon, 0 );
|
|
self TakeWeapon( weapon );
|
|
}
|
|
|
|
self waittill( "player_revived" );
|
|
|
|
if ( self.lsgsar_has_lethal_nade )
|
|
{
|
|
self zm_utility::set_player_lethal_grenade( self.lsgsar_lethal );
|
|
self GiveWeapon( self.lsgsar_lethal );
|
|
self SetWeaponAmmoClip( self.lsgsar_lethal, self.lsgsar_lethal_nade_amt );
|
|
}
|
|
|
|
if ( self.lsgsar_has_tactical_nade )
|
|
{
|
|
self zm_utility::set_player_tactical_grenade( self.lsgsar_tactical );
|
|
self GiveWeapon( self.lsgsar_tactical );
|
|
self SetWeaponAmmoClip( self.lsgsar_tactical, self.lsgsar_tactical_nade_amt );
|
|
}
|
|
|
|
self.lsgsar_lethal_nade_amt = undefined;
|
|
self.lsgsar_has_lethal_nade = undefined;
|
|
self.lsgsar_tactical_nade_amt = undefined;
|
|
self.lsgsar_has_tactical_nade = undefined;
|
|
self.lsgsar_lethal = undefined;
|
|
self.lsgsar_tactical = undefined;
|
|
|
|
}
|
|
|
|
function spectators_respawn()
|
|
{
|
|
level endon( "between_round_over" );
|
|
|
|
if( !IsDefined( level.zombie_vars["spectators_respawn"] ) || !level.zombie_vars["spectators_respawn"] )
|
|
{
|
|
return;
|
|
}
|
|
|
|
while( 1 )
|
|
{
|
|
players = GetPlayers();
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
e_player = players[i];
|
|
e_player spectator_respawn_player();
|
|
}
|
|
|
|
wait( 1 );
|
|
}
|
|
}
|
|
|
|
function spectator_respawn_player()
|
|
{
|
|
if( self.sessionstate == "spectator" && IsDefined( self.spectator_respawn ))
|
|
{
|
|
if( !IsDefined( level.custom_spawnPlayer ) )
|
|
{
|
|
// Custom spawn call for when they respawn from spectator
|
|
level.custom_spawnPlayer = &spectator_respawn;
|
|
}
|
|
|
|
self [[level.spawnPlayer]]();
|
|
thread refresh_player_navcard_hud();
|
|
if (isDefined(level.script) && level.round_number > 6 && self.score < 1500)
|
|
{
|
|
self.old_score = self.score;
|
|
if(isDefined(level.spectator_respawn_custom_score))
|
|
{
|
|
self [[level.spectator_respawn_custom_score]]();
|
|
}
|
|
self.score = 1500;
|
|
}
|
|
}
|
|
}
|
|
|
|
function spectator_respawn()
|
|
{
|
|
/# println( "*************************Respawn Spectator***" ); #/
|
|
assert( IsDefined( self.spectator_respawn ) );
|
|
|
|
origin = self.spectator_respawn.origin;
|
|
angles = self.spectator_respawn.angles;
|
|
|
|
self setSpectatePermissions( false );
|
|
|
|
new_origin = undefined;
|
|
|
|
|
|
if ( isdefined( level.check_valid_spawn_override ) )
|
|
{
|
|
new_origin = [[ level.check_valid_spawn_override ]]( self );
|
|
}
|
|
|
|
if ( !isdefined( new_origin ) )
|
|
{
|
|
new_origin = check_for_valid_spawn_near_team( self,true );
|
|
}
|
|
|
|
|
|
if( IsDefined( new_origin ) )
|
|
{
|
|
if(!isDefined(new_origin.angles))
|
|
{
|
|
angles = (0, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
angles = new_origin.angles;
|
|
}
|
|
self Spawn( new_origin.origin, angles );
|
|
}
|
|
else
|
|
{
|
|
self Spawn( origin, angles );
|
|
}
|
|
|
|
|
|
if ( IsDefined( self zm_utility::get_player_placeable_mine() ) )
|
|
{
|
|
self TakeWeapon( self zm_utility::get_player_placeable_mine() );
|
|
self zm_utility::set_player_placeable_mine( level.weaponNone );
|
|
}
|
|
|
|
self zm_equipment::take();
|
|
|
|
self.is_burning = undefined;
|
|
self.abilities = [];
|
|
|
|
// The check_for_level_end looks for this
|
|
self.is_zombie = false;
|
|
zm_laststand::set_ignoreme( false );
|
|
|
|
self clientfield::set( "zmbLastStand", 0 );
|
|
self RevivePlayer();
|
|
|
|
self notify( "spawned_player" );
|
|
self callback::callback( #"on_player_spawned" );
|
|
|
|
if(IsDefined(level._zombiemode_post_respawn_callback))
|
|
{
|
|
self thread [[level._zombiemode_post_respawn_callback]]();
|
|
}
|
|
|
|
// Penalize the player when we respawn, since he 'died'
|
|
self zm_score::player_reduce_points( "died" );
|
|
|
|
self zm_melee_weapon::spectator_respawn_all();
|
|
|
|
self thread player_zombie_breadcrumb();
|
|
|
|
self thread zm_perks::return_retained_perks();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function check_for_valid_spawn_near_team( revivee, return_struct )
|
|
{
|
|
// if level override is detected, use it instead of normal respawn logic
|
|
if ( IsDefined( level.check_for_valid_spawn_near_team_callback ) )
|
|
{
|
|
spawn_location = [[ level.check_for_valid_spawn_near_team_callback ]](revivee, return_struct);
|
|
return spawn_location;
|
|
}
|
|
else // normal respawn logic below here
|
|
{
|
|
players = GetPlayers();
|
|
spawn_points = zm_gametype::get_player_spawns_for_gametype();
|
|
|
|
closest_group = undefined;
|
|
closest_distance = 100000000;
|
|
backup_group = undefined;
|
|
backup_distance = 100000000;
|
|
|
|
if( spawn_points.size == 0 )
|
|
return undefined;
|
|
|
|
a_enabled_zone_entities = zm_zonemgr::get_active_zones_entities();
|
|
|
|
// Look for the closest group that is within the specified ideal distances
|
|
// If we can't find one within a valid area, use the closest unlocked group.
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
if( zm_utility::is_player_valid( players[i],undefined,true ) && (players[i] != self) )
|
|
{
|
|
for( j = 0 ; j < spawn_points.size; j++ )
|
|
{
|
|
if( isdefined(spawn_points[j].script_int) )
|
|
ideal_distance = spawn_points[j].script_int;
|
|
else
|
|
ideal_distance = 1000;
|
|
|
|
// Safety check, check the spawn point is inside an enabled zone
|
|
// There have been cases where a spawn point has the wrong zone KVP on it compared to the zone it exists inside
|
|
if ( zm_utility::check_point_in_enabled_zone( spawn_points[j].origin, false, a_enabled_zone_entities ) == false )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( spawn_points[j].locked == false )
|
|
{
|
|
plyr_dist = DistanceSquared( players[i].origin, spawn_points[j].origin );
|
|
if( plyr_dist < ( ideal_distance * ideal_distance ) )
|
|
{
|
|
if ( plyr_dist < closest_distance )
|
|
{
|
|
closest_distance = plyr_dist;
|
|
closest_group = j;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( plyr_dist < backup_distance )
|
|
{
|
|
backup_group = j;
|
|
backup_distance = plyr_dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we don't have a closest_group, let's use the backup
|
|
if( !IsDefined( closest_group ) )
|
|
{
|
|
closest_group = backup_group;
|
|
}
|
|
|
|
if( IsDefined( closest_group ) )
|
|
{
|
|
spawn_location = get_valid_spawn_location( revivee, spawn_points, closest_group, return_struct );
|
|
if( IsDefined(spawn_location) )
|
|
{
|
|
return( spawn_location );
|
|
}
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function get_valid_spawn_location( revivee, spawn_points, closest_group, return_struct )
|
|
{
|
|
spawn_array =struct::get_array( spawn_points[closest_group].target, "targetname" );
|
|
spawn_array = array::randomize(spawn_array);
|
|
|
|
for( k = 0; k < spawn_array.size; k++ )
|
|
{
|
|
if(IsDefined(spawn_array[k].plyr) && spawn_array[k].plyr == revivee GetEntityNumber())
|
|
{
|
|
if(positionWouldTelefrag(spawn_array[k].origin))
|
|
{
|
|
spawn_array[k].plyr = undefined;
|
|
break;
|
|
}
|
|
else if(( isdefined( return_struct ) && return_struct ))
|
|
{
|
|
return spawn_array[k];
|
|
}
|
|
else
|
|
{
|
|
return spawn_array[k].origin;
|
|
}
|
|
}
|
|
}
|
|
|
|
for( k = 0; k < spawn_array.size; k++ )
|
|
{
|
|
if(positionWouldTelefrag(spawn_array[k].origin))
|
|
{
|
|
continue;
|
|
}
|
|
if(!IsDefined(spawn_array[k].plyr) || spawn_array[k].plyr == revivee GetEntityNumber())
|
|
{
|
|
spawn_array[k].plyr = revivee GetEntityNumber();
|
|
if(( isdefined( return_struct ) && return_struct ))
|
|
{
|
|
return spawn_array[k];
|
|
}
|
|
else
|
|
{
|
|
return spawn_array[k].origin;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(( isdefined( return_struct ) && return_struct ))
|
|
{
|
|
return spawn_array[0];
|
|
}
|
|
|
|
return spawn_array[0].origin;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function check_for_valid_spawn_near_position( revivee, v_position, return_struct )
|
|
{
|
|
spawn_points = zm_gametype::get_player_spawns_for_gametype();
|
|
|
|
if( spawn_points.size == 0 )
|
|
{
|
|
return( undefined );
|
|
}
|
|
|
|
closest_group = undefined;
|
|
closest_distance = 100000000;
|
|
backup_group = undefined;
|
|
backup_distance = 100000000;
|
|
|
|
for( i=0 ; i<spawn_points.size; i++ )
|
|
{
|
|
if( IsDefined(spawn_points[i].script_int) )
|
|
{
|
|
ideal_distance = spawn_points[i].script_int;
|
|
}
|
|
else
|
|
{
|
|
ideal_distance = 1000;
|
|
}
|
|
|
|
if ( spawn_points[i].locked == false )
|
|
{
|
|
dist = DistanceSquared( v_position, spawn_points[i].origin );
|
|
if( dist < ( ideal_distance * ideal_distance ) )
|
|
{
|
|
if ( dist < closest_distance )
|
|
{
|
|
closest_distance = dist;
|
|
closest_group = i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( dist < backup_distance )
|
|
{
|
|
backup_group = i;
|
|
backup_distance = dist;
|
|
}
|
|
}
|
|
}
|
|
// If we don't have a closest_group, let's use the backup
|
|
if ( !IsDefined( closest_group ) )
|
|
{
|
|
closest_group = backup_group;
|
|
}
|
|
}
|
|
|
|
if( IsDefined( closest_group ) )
|
|
{
|
|
spawn_location = get_valid_spawn_location( revivee, spawn_points, closest_group, return_struct );
|
|
if( IsDefined(spawn_location) )
|
|
{
|
|
return( spawn_location );
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
|
|
|
|
//*****************************************************************************
|
|
// Get a valid spawn point within the (min_distance, max_distance) ranges
|
|
//*****************************************************************************
|
|
|
|
function check_for_valid_spawn_within_range( revivee, v_position, return_struct, min_distance, max_distance )
|
|
{
|
|
spawn_points = zm_gametype::get_player_spawns_for_gametype();
|
|
|
|
if( spawn_points.size == 0 )
|
|
{
|
|
return( undefined );
|
|
}
|
|
|
|
closest_group = undefined;
|
|
closest_distance = 100000000;
|
|
|
|
for( i=0 ; i<spawn_points.size; i++ )
|
|
{
|
|
if ( spawn_points[i].locked == false )
|
|
{
|
|
dist = Distance( v_position, spawn_points[i].origin );
|
|
if( (dist >= min_distance) && (dist <= max_distance) )
|
|
{
|
|
if( dist < closest_distance )
|
|
{
|
|
closest_distance = dist;
|
|
closest_group = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( IsDefined( closest_group ) )
|
|
{
|
|
spawn_location = get_valid_spawn_location( revivee, spawn_points, closest_group, return_struct );
|
|
if( IsDefined(spawn_location) )
|
|
{
|
|
return( spawn_location );
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function get_players_on_team(exclude)
|
|
{
|
|
teammates = [];
|
|
|
|
players = GetPlayers();
|
|
for(i=0;i<players.size;i++)
|
|
{
|
|
//check to see if other players on your team are alive and not waiting to be revived
|
|
if(players[i].spawn_side == self.spawn_side && !isDefined(players[i].revivetrigger) && players[i] != exclude )
|
|
{
|
|
teammates[teammates.size] = players[i];
|
|
}
|
|
}
|
|
|
|
return teammates;
|
|
}
|
|
|
|
|
|
|
|
function get_safe_breadcrumb_pos( player )
|
|
{
|
|
players = GetPlayers();
|
|
valid_players = [];
|
|
|
|
min_dist = 150 * 150;
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
if( !zm_utility::is_player_valid( players[i] ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
valid_players[valid_players.size] = players[i];
|
|
}
|
|
|
|
for( i = 0; i < valid_players.size; i++ )
|
|
{
|
|
count = 0;
|
|
for( q = 1; q < player.zombie_breadcrumbs.size; q++ )
|
|
{
|
|
if( DistanceSquared( player.zombie_breadcrumbs[q], valid_players[i].origin ) < min_dist )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
count++;
|
|
if( count == valid_players.size )
|
|
{
|
|
return player.zombie_breadcrumbs[q];
|
|
}
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
function round_spawning()
|
|
{
|
|
level endon( "intermission" );
|
|
level endon( "end_of_round" );
|
|
level endon( "restart_round" );
|
|
/#
|
|
level endon( "kill_round" );
|
|
#/
|
|
|
|
if( level.intermission )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( cheat_enabled( 2 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( level.zm_loc_types[ "zombie_location" ].size < 1 )
|
|
{
|
|
ASSERTMSG( "No active spawners in the map. Check to see if the zone is active and if it's pointing to spawners." );
|
|
return;
|
|
}
|
|
|
|
zombie_utility::ai_calculate_health( level.round_number );
|
|
|
|
count = 0;
|
|
|
|
//CODER MOD: TOMMY K
|
|
players = GetPlayers();
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
players[i].zombification_time = 0;
|
|
}
|
|
|
|
// Now set the total for the new round, except when it's already been set by the kill counter
|
|
if ( !( IsDefined( level.kill_counter_hud ) && level.zombie_total > 0 ) )
|
|
{
|
|
level.zombie_total = get_zombie_count_for_round( level.round_number, level.players.size );
|
|
level.zombie_respawns = 0; // reset number of zombies needing respawn
|
|
level notify( "zombie_total_set" );
|
|
}
|
|
|
|
if ( IsDefined( level.zombie_total_set_func ) )
|
|
{
|
|
level thread [[ level.zombie_total_set_func ]]();
|
|
}
|
|
|
|
if ( level.round_number < 10 || level.speed_change_max > 0 )
|
|
{
|
|
level thread zombie_utility::zombie_speed_up();
|
|
}
|
|
|
|
old_spawn = undefined;
|
|
while( 1 )
|
|
{
|
|
while( zombie_utility::get_current_zombie_count() >= level.zombie_ai_limit || level.zombie_total <= 0 )
|
|
{
|
|
wait( 0.1 );
|
|
}
|
|
|
|
while ( zombie_utility::get_current_actor_count() >= level.zombie_actor_limit )
|
|
{
|
|
zombie_utility::clear_all_corpses();
|
|
wait( 0.1 );
|
|
}
|
|
|
|
// if we're using something that can pause the world, wait until finished to continue spawning
|
|
if(flag::exists("world_is_paused"))
|
|
{
|
|
level flag::wait_till_clear("world_is_paused");
|
|
}
|
|
|
|
// added ability to pause zombie spawning
|
|
level flag::wait_till( "spawn_zombies" );
|
|
|
|
//Not great fix for this being zero - which it should NEVER be! (2 days to ship - PETER)
|
|
while( level.zm_loc_types[ "zombie_location" ].size <= 0 )
|
|
{
|
|
wait( 0.1 );
|
|
}
|
|
|
|
run_custom_ai_spawn_checks();
|
|
|
|
if ( ( isdefined( level.hostMigrationTimer ) && level.hostMigrationTimer ) )
|
|
{
|
|
util::wait_network_frame();
|
|
continue;
|
|
}
|
|
|
|
// Run custom round spawn logic - returns TRUE if we spawned something, FALSE if we need to spawn a zombie.
|
|
if ( isdefined( level.fn_custom_round_ai_spawn ) )
|
|
{
|
|
if ( [[ level.fn_custom_round_ai_spawn ]]() )
|
|
{
|
|
// we handled the spawn
|
|
util::wait_network_frame();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if( IsDefined( level.zombie_spawners ) )
|
|
{
|
|
// Check for custom zombie spawner selection
|
|
if ( isdefined( level.fn_custom_zombie_spawner_selection ) )
|
|
{
|
|
spawner = [[ level.fn_custom_zombie_spawner_selection ]]();
|
|
}
|
|
|
|
// Default zombie spawner selection
|
|
else
|
|
{
|
|
if( ( isdefined( level.use_multiple_spawns ) && level.use_multiple_spawns ) )
|
|
{
|
|
if( isdefined( level.spawner_int ) && ( isdefined( level.zombie_spawn[level.spawner_int].size ) && level.zombie_spawn[level.spawner_int].size ) )
|
|
{
|
|
spawner = array::random( level.zombie_spawn[level.spawner_int] );
|
|
}
|
|
else
|
|
{
|
|
spawner = array::random( level.zombie_spawners );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spawner = array::random( level.zombie_spawners );
|
|
}
|
|
}
|
|
|
|
ai = zombie_utility::spawn_zombie( spawner, spawner.targetname );
|
|
}
|
|
|
|
if( IsDefined( ai ) )
|
|
{
|
|
level.zombie_total--;
|
|
if ( level.zombie_respawns > 0 )
|
|
{
|
|
level.zombie_respawns--;
|
|
}
|
|
|
|
ai thread zombie_utility::round_spawn_failsafe();
|
|
count++;
|
|
|
|
if ( ai ai::has_behavior_attribute( "can_juke" ) )
|
|
{
|
|
ai ai::set_behavior_attribute("can_juke", false);
|
|
}
|
|
|
|
// Get zombies into the map quicker if they're respawning from cleanup
|
|
if ( level.zombie_respawns > 0 )//&& level.zombie_vars["zombie_spawn_delay"] > 1.0 )
|
|
{
|
|
wait 0.1;
|
|
}
|
|
else
|
|
{
|
|
wait( level.zombie_vars["zombie_spawn_delay"] );
|
|
}
|
|
}
|
|
|
|
util::wait_network_frame();
|
|
}
|
|
}
|
|
|
|
function get_zombie_count_for_round( n_round, n_player_count )
|
|
{
|
|
max = level.zombie_vars["zombie_max_ai"];
|
|
|
|
multiplier = n_round / 5;
|
|
if( multiplier < 1 )
|
|
{
|
|
multiplier = 1;
|
|
}
|
|
|
|
// After round 10, exponentially have more AI attack the player
|
|
if( n_round >= 10 )
|
|
{
|
|
multiplier *= n_round * 0.15;
|
|
}
|
|
|
|
if( n_player_count == 1 )
|
|
{
|
|
max += int( ( 0.5 * level.zombie_vars["zombie_ai_per_player"] ) * multiplier );
|
|
}
|
|
else
|
|
{
|
|
max += int( ( ( n_player_count - 1 ) * level.zombie_vars["zombie_ai_per_player"] ) * multiplier );
|
|
}
|
|
|
|
if( !isDefined( level.max_zombie_func ) )
|
|
{
|
|
level.max_zombie_func = &zombie_utility::default_max_zombie_func;
|
|
}
|
|
|
|
n_zombie_count = [[ level.max_zombie_func ]]( max, n_round );
|
|
|
|
return n_zombie_count;
|
|
}
|
|
|
|
// Add custom ai (quads, etc.) to zombie spawner arrays for spawning
|
|
function run_custom_ai_spawn_checks()
|
|
{
|
|
foreach ( str_id, s in level.custom_ai_spawn_check_funcs )
|
|
{
|
|
if ( [[ s.func_check ]]() )
|
|
{
|
|
a_spawners = [[ s.func_get_spawners ]]();
|
|
level.zombie_spawners = ArrayCombine( level.zombie_spawners, a_spawners, false, false );
|
|
|
|
if ( ( isdefined( level.use_multiple_spawns ) && level.use_multiple_spawns ) )
|
|
{
|
|
foreach ( sp in a_spawners )
|
|
{
|
|
if ( IsDefined( sp.script_int ) )
|
|
{
|
|
if ( !IsDefined( level.zombie_spawn[ sp.script_int ] ) )
|
|
{
|
|
level.zombie_spawn[ sp.script_int ] = [];
|
|
}
|
|
|
|
if ( !IsInArray( level.zombie_spawn[ sp.script_int ], sp ) )
|
|
{
|
|
if ( !isdefined( level.zombie_spawn[ sp.script_int ] ) ) level.zombie_spawn[ sp.script_int ] = []; else if ( !IsArray( level.zombie_spawn[ sp.script_int ] ) ) level.zombie_spawn[ sp.script_int ] = array( level.zombie_spawn[ sp.script_int ] ); level.zombie_spawn[ sp.script_int ][level.zombie_spawn[ sp.script_int ].size]=sp;;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( IsDefined( s.func_get_locations ) )
|
|
{
|
|
a_locations = [[ s.func_get_locations ]]();
|
|
level.zm_loc_types[ "zombie_location" ] = ArrayCombine( level.zm_loc_types[ "zombie_location" ], a_locations, false, false );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
a_spawners = [[ s.func_get_spawners ]]();
|
|
|
|
foreach ( sp in a_spawners )
|
|
{
|
|
ArrayRemoveValue( level.zombie_spawners, sp );
|
|
}
|
|
|
|
if ( ( isdefined( level.use_multiple_spawns ) && level.use_multiple_spawns ) )
|
|
{
|
|
foreach ( sp in a_spawners )
|
|
{
|
|
if ( IsDefined( sp.script_int ) && IsDefined( level.zombie_spawn[ sp.script_int ] ) )
|
|
{
|
|
ArrayRemoveValue( level.zombie_spawn[ sp.script_int ], sp );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( IsDefined( s.func_get_locations ) )
|
|
{
|
|
a_locations = [[ s.func_get_locations ]]();
|
|
|
|
foreach ( s_loc in a_locations )
|
|
{
|
|
ArrayRemoveValue( level.zm_loc_types[ "zombie_location" ], s_loc );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function register_custom_ai_spawn_check( str_id, func_check, func_get_spawners, func_get_locations )
|
|
{
|
|
if ( !IsDefined( level.custom_ai_spawn_check_funcs[str_id] ) )
|
|
{
|
|
level.custom_ai_spawn_check_funcs[ str_id ] = SpawnStruct();
|
|
}
|
|
|
|
level.custom_ai_spawn_check_funcs[ str_id ].func_check = func_check;
|
|
level.custom_ai_spawn_check_funcs[ str_id ].func_get_spawners = func_get_spawners;
|
|
level.custom_ai_spawn_check_funcs[ str_id ].func_get_locations = func_get_locations;
|
|
}
|
|
|
|
// TESTING: spawn one zombie at a time
|
|
function round_spawning_test()
|
|
{
|
|
while (true)
|
|
{
|
|
spawn_point = array::random( level.zm_loc_types[ "zombie_location" ] ); // grab a random spawner
|
|
|
|
spawner = array::random(level.zombie_spawners);
|
|
ai = zombie_utility::spawn_zombie( spawner,spawner.targetname,spawn_point);
|
|
|
|
ai waittill("death");
|
|
|
|
wait 5;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
|
|
// round_text( text )
|
|
// {
|
|
// if( level.first_round )
|
|
// {
|
|
// intro = true;
|
|
// }
|
|
// else
|
|
// {
|
|
// intro = false;
|
|
// }
|
|
//
|
|
// hud = create_simple_hud();
|
|
// hud.horzAlign = "center";
|
|
// hud.vertAlign = "middle";
|
|
// hud.alignX = "center";
|
|
// hud.alignY = "middle";
|
|
// hud.y = -100;
|
|
// hud.foreground = 1;
|
|
// hud.fontscale = 16.0;
|
|
// hud.alpha = 0;
|
|
// hud.color = ( 1, 1, 1 );
|
|
//
|
|
// hud SetText( text );
|
|
// hud FadeOverTime( 1.5 );
|
|
// hud.alpha = 1;
|
|
// wait( 1.5 );
|
|
//
|
|
// if( intro )
|
|
// {
|
|
// wait( 1 );
|
|
// level notify( "intro_change_color" );
|
|
// }
|
|
//
|
|
// hud FadeOverTime( 3 );
|
|
// //hud.color = ( 0.8, 0, 0 );
|
|
// hud.color = ( 0.21, 0, 0 );
|
|
// wait( 3 );
|
|
//
|
|
// if( intro )
|
|
// {
|
|
// level waittill( "intro_hud_done" );
|
|
// }
|
|
//
|
|
// hud FadeOverTime( 1.5 );
|
|
// hud.alpha = 0;
|
|
// wait( 1.5 );
|
|
// hud destroy();
|
|
// }
|
|
|
|
|
|
// Allows the round to be paused. Displays a countdown timer.
|
|
//
|
|
function round_pause( delay )
|
|
{
|
|
if ( !IsDefined( delay ) )
|
|
{
|
|
delay = 30;
|
|
}
|
|
|
|
level.countdown_hud = zm_utility::create_counter_hud();
|
|
level.countdown_hud SetValue( delay );
|
|
level.countdown_hud.color = ( 1, 1, 1 );
|
|
level.countdown_hud.alpha = 1;
|
|
level.countdown_hud FadeOverTime( 2.0 );
|
|
wait( 2.0 );
|
|
|
|
level.countdown_hud.color = ( 0.21, 0, 0 );
|
|
level.countdown_hud FadeOverTime( 3.0 );
|
|
wait(3);
|
|
|
|
while (delay >= 1)
|
|
{
|
|
wait (1);
|
|
delay--;
|
|
level.countdown_hud SetValue( delay );
|
|
}
|
|
|
|
// Zero! Play end sound
|
|
players = GetPlayers();
|
|
for (i=0; i<players.size; i++ )
|
|
{
|
|
players[i] playlocalsound( "zmb_perks_packa_ready" );
|
|
}
|
|
|
|
level.countdown_hud FadeOverTime( 1.0 );
|
|
level.countdown_hud.color = (1,1,1);
|
|
level.countdown_hud.alpha = 0;
|
|
wait( 1.0 );
|
|
|
|
level.countdown_hud zm_utility::destroy_hud();
|
|
}
|
|
|
|
|
|
// Zombie spawning
|
|
//
|
|
function round_start()
|
|
{
|
|
if ( !isdefined( level.zombie_spawners) || level.zombie_spawners.size == 0 )
|
|
{
|
|
/#PrintLn("***Warning: No spawners found for this level.***");#/
|
|
level flag::set( "begin_spawning" );
|
|
return;
|
|
}
|
|
/# PrintLn( "ZM >> round_start start" ); #/
|
|
|
|
if ( IsDefined(level.round_prestart_func) )
|
|
{
|
|
[[ level.round_prestart_func ]]();
|
|
}
|
|
else
|
|
{
|
|
n_delay = 2;
|
|
|
|
if ( IsDefined( level.zombie_round_start_delay ) )
|
|
{
|
|
n_delay = level.zombie_round_start_delay;
|
|
}
|
|
|
|
wait n_delay;
|
|
}
|
|
|
|
level.zombie_health = level.zombie_vars["zombie_health_start"];
|
|
|
|
if( GetDvarInt( "scr_writeconfigstrings" ) == 1 )
|
|
{
|
|
wait(5);
|
|
ExitLevel();
|
|
return;
|
|
}
|
|
|
|
if ( level.zombie_vars["game_start_delay"] > 0 )
|
|
{
|
|
round_pause( level.zombie_vars["game_start_delay"] );
|
|
}
|
|
|
|
level flag::set( "begin_spawning" );
|
|
|
|
if( !isDefined(level.round_spawn_func) )
|
|
{
|
|
level.round_spawn_func = &round_spawning;
|
|
}
|
|
|
|
if(!IsDefined(level.move_spawn_func))
|
|
{
|
|
level.move_spawn_func = &zm_utility::move_zombie_spawn_location;
|
|
}
|
|
|
|
/#
|
|
if (GetDvarInt( "zombie_rise_test") )
|
|
{
|
|
level.round_spawn_func = &round_spawning_test; // FOR TESTING, one zombie at a time, no round advancement
|
|
}
|
|
#/
|
|
|
|
if ( !isDefined(level.round_wait_func) )
|
|
{
|
|
level.round_wait_func = &round_wait;
|
|
}
|
|
|
|
if ( !IsDefined(level.round_think_func) )
|
|
{
|
|
level.round_think_func = &round_think;
|
|
}
|
|
|
|
|
|
level thread [[ level.round_think_func ]]();
|
|
}
|
|
|
|
//
|
|
// Lets the players know that you need power to open these
|
|
function play_door_dialog()
|
|
{
|
|
self endon ("warning_dialog");
|
|
timer = 0;
|
|
|
|
while(1)
|
|
{
|
|
{wait(.05);};
|
|
players = GetPlayers();
|
|
for(i = 0; i < players.size; i++)
|
|
{
|
|
dist = distancesquared(players[i].origin, self.origin );
|
|
if(dist > 70*70)
|
|
{
|
|
timer =0;
|
|
continue;
|
|
}
|
|
while(dist < 70*70 && timer < 3)
|
|
{
|
|
wait(0.5);
|
|
timer++;
|
|
}
|
|
if(dist > 70*70 && timer >= 3)
|
|
{
|
|
self playsound("door_deny");
|
|
|
|
players[i] zm_audio::create_and_play_dialog( "general", "outofmoney" );
|
|
wait(3);
|
|
self notify ("warning_dialog");
|
|
//iprintlnbold("warning_given");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function wait_until_first_player()
|
|
{
|
|
players = GetPlayers();
|
|
if( !IsDefined( players[0] ) )
|
|
{
|
|
level waittill( "first_player_ready" );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the current round number hud display
|
|
function round_one_up()
|
|
{
|
|
level endon("end_game");
|
|
if( isdefined(level.noRoundNumber) && level.noRoundNumber==true )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(!IsDefined(level.doground_nomusic))
|
|
{
|
|
level.doground_nomusic = 0;
|
|
}
|
|
|
|
if( level.first_round )
|
|
{
|
|
intro = true;
|
|
if( isdefined( level._custom_intro_vox ) )
|
|
{
|
|
level thread [[level._custom_intro_vox]]();
|
|
}
|
|
else
|
|
{
|
|
level thread play_level_start_vox_delayed();
|
|
};
|
|
}
|
|
else
|
|
{
|
|
intro = false;
|
|
}
|
|
|
|
//Round Number Specific Lines
|
|
if( level.round_number == 5 || level.round_number == 10 || level.round_number == 20 || level.round_number == 35 || level.round_number == 50 )
|
|
{
|
|
players = GetPlayers();
|
|
rand = RandomIntRange(0,players.size);
|
|
players[rand] thread zm_audio::create_and_play_dialog( "general", "round_" + level.round_number );
|
|
}
|
|
|
|
if( intro )
|
|
{
|
|
if(( isdefined( level.host_ended_game ) && level.host_ended_game ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
wait( 6.25 );
|
|
level notify( "intro_hud_done" );
|
|
wait( 2 );
|
|
|
|
}
|
|
else
|
|
{
|
|
wait( 2.5 );
|
|
}
|
|
|
|
ReportMTU(level.round_number); // In network debug instrumented builds, causes network spike report to generate.
|
|
}
|
|
|
|
|
|
// Flash the round display at the end of the round
|
|
//
|
|
function round_over()
|
|
{
|
|
if( isdefined(level.noRoundNumber) && level.noRoundNumber==true )
|
|
{
|
|
return;
|
|
}
|
|
|
|
time = [[level.func_get_delay_between_rounds]]();
|
|
|
|
players = GetPlayers();
|
|
for ( player_index = 0; player_index < players.size; player_index++ )
|
|
{
|
|
if ( !IsDefined( players[player_index].pers["previous_distance_traveled"] ) )
|
|
{
|
|
players[player_index].pers["previous_distance_traveled"] = 0;
|
|
}
|
|
distanceThisRound = int( players[player_index].pers["distance_traveled"] - players[player_index].pers["previous_distance_traveled"] );
|
|
players[player_index].pers["previous_distance_traveled"] = players[player_index].pers["distance_traveled"];
|
|
players[player_index] IncrementPlayerStat("distance_traveled", distanceThisRound );
|
|
if ( players[player_index].pers["team"] != "spectator" )
|
|
{
|
|
players[player_index] recordRoundEndStats();
|
|
}
|
|
}
|
|
RecordZombieRoundEnd();
|
|
// waiting for the Pulse from lua
|
|
wait( time );
|
|
}
|
|
|
|
function get_delay_between_rounds()
|
|
{
|
|
return( level.zombie_vars["zombie_between_round_time"] );
|
|
}
|
|
|
|
function recordPlayerRoundWeapon(weapon, statname)
|
|
{
|
|
if (isDefined(weapon))
|
|
{
|
|
weaponIdx = GetBaseWeaponItemIndex(weapon);
|
|
if (isDefined(weaponIdx))
|
|
{
|
|
self incrementplayerstat(statname, weaponIdx);
|
|
}
|
|
}
|
|
}
|
|
|
|
function recordPrimaryWeaponsStats(base_stat_name, max_weapons)
|
|
{
|
|
current_weapons = self GetWeaponsListPrimaries();
|
|
for (index = 0; index < max_weapons && index < current_weapons.size; index++)
|
|
{
|
|
recordPlayerRoundWeapon(current_weapons[index], base_stat_name + index);
|
|
}
|
|
}
|
|
|
|
function recordRoundStartStats() //self == player
|
|
{
|
|
zoneName = self zm_utility::get_current_zone();
|
|
if( IsDefined(zoneName) )
|
|
{
|
|
self RecordZombieZone("startingZone", zoneName);
|
|
}
|
|
|
|
self incrementplayerstat("score", self.score);
|
|
primaryWeapon = self GetCurrentWeapon();
|
|
|
|
self recordPrimaryWeaponsStats("roundStartPrimaryWeapon", 3);
|
|
self RecordMapEvent(8, GetTime(), self.origin, level.round_number);
|
|
}
|
|
|
|
function recordRoundEndStats() //self == player
|
|
{
|
|
zoneName = self zm_utility::get_current_zone();
|
|
if( IsDefined(zoneName) )
|
|
{
|
|
self RecordZombieZone( "endingZone", zoneName );
|
|
}
|
|
|
|
self recordPrimaryWeaponsStats("roundEndPrimaryWeapon", 3);
|
|
self RecordMapEvent(9, GetTime(), self.origin, level.round_number);
|
|
}
|
|
|
|
function round_think( restart = false )
|
|
{
|
|
/# PrintLn( "ZM >> round_think start" ); #/
|
|
|
|
level endon("end_round_think");
|
|
|
|
if(!( isdefined( restart ) && restart ))
|
|
{
|
|
// Wait for blackscreen to end if in use
|
|
if ( IsDefined( level.initial_round_wait_func ))
|
|
[[level.initial_round_wait_func]]();
|
|
|
|
if(!( isdefined( level.host_ended_game ) && level.host_ended_game ))
|
|
{
|
|
//unfreeze the players controls now
|
|
players = GetPlayers();
|
|
foreach(player in players)
|
|
{
|
|
if(!( isdefined( player.hostMigrationControlsFrozen ) && player.hostMigrationControlsFrozen ))
|
|
{
|
|
player FreezeControls(false);
|
|
/# println(" Unfreeze controls 8"); #/
|
|
}
|
|
|
|
// set the initial round_number
|
|
player zm_stats::set_global_stat( "rounds", level.round_number );
|
|
}
|
|
}
|
|
}
|
|
|
|
SetRoundsPlayed( level.round_number );
|
|
|
|
for( ;; )
|
|
{
|
|
//////////////////////////////////////////
|
|
//designed by prod DT#36173
|
|
maxreward = 50 * level.round_number;
|
|
if ( maxreward > 500 )
|
|
maxreward = 500;
|
|
level.zombie_vars["rebuild_barrier_cap_per_round"] = maxreward;
|
|
//////////////////////////////////////////
|
|
|
|
level.pro_tips_start_time = GetTime();
|
|
level.zombie_last_run_time = GetTime(); // Resets the last time a zombie ran
|
|
|
|
if ( IsDefined( level.zombie_round_change_custom ) )
|
|
{
|
|
[[ level.zombie_round_change_custom ]]();
|
|
}
|
|
else
|
|
{
|
|
if( !( isdefined( level.sndMusicSpecialRound ) && level.sndMusicSpecialRound ) )
|
|
{
|
|
if( ( isdefined( level.sndGotoRoundOccurred ) && level.sndGotoRoundOccurred ))
|
|
level.sndGotoRoundOccurred = false;
|
|
else if( level.round_number == 1 )
|
|
level thread zm_audio::sndMusicSystem_PlayState( "round_start_first" );
|
|
else if( level.round_number <= 5 )
|
|
level thread zm_audio::sndMusicSystem_PlayState( "round_start" );
|
|
else
|
|
level thread zm_audio::sndMusicSystem_PlayState( "round_start_short" );
|
|
}
|
|
round_one_up();
|
|
// round_text( &"ZOMBIE_ROUND_BEGIN" );
|
|
}
|
|
|
|
zm_powerups::powerup_round_start();
|
|
|
|
players = GetPlayers();
|
|
array::thread_all( players, &zm_blockers::rebuild_barrier_reward_reset );
|
|
|
|
if(!( isdefined( level.headshots_only ) && level.headshots_only ) && !restart ) //no grenades for headshot only mode, or when grief restarts the round after everyone dies
|
|
{
|
|
level thread award_grenades_for_survivors();
|
|
}
|
|
|
|
/# PrintLn( "ZM >> round_think, round="+level.round_number+", player_count=" + players.size ); #/
|
|
|
|
level.round_start_time = GetTime();
|
|
|
|
//Not great fix for this being zero - which it should NEVER be! (post ship - PETER)
|
|
while( level.zm_loc_types[ "zombie_location" ].size <= 0 )
|
|
{
|
|
wait( 0.1 );
|
|
}
|
|
|
|
/#
|
|
//Reset spawn counter for zones
|
|
zkeys = GetArrayKeys( level.zones );
|
|
for ( i = 0; i < zkeys.size; i++ )
|
|
{
|
|
zoneName = zkeys[i];
|
|
level.zones[zoneName].round_spawn_count = 0;
|
|
}
|
|
#/
|
|
|
|
level thread [[level.round_spawn_func]]();
|
|
|
|
level notify( "start_of_round" );
|
|
RecordZombieRoundStart();
|
|
bb::logRoundEvent("start_of_round");
|
|
players = GetPlayers();
|
|
for ( index = 0; index < players.size; index++ )
|
|
{
|
|
players[index] recordRoundStartStats();
|
|
}
|
|
if(isDefined(level.round_start_custom_func))
|
|
{
|
|
[[level.round_start_custom_func]]();
|
|
}
|
|
|
|
[[level.round_wait_func]]();
|
|
|
|
level.first_round = false;
|
|
level notify( "end_of_round" );
|
|
bb::logRoundEvent("end_of_round");
|
|
UploadStats();
|
|
|
|
if(isDefined(level.round_end_custom_logic))
|
|
{
|
|
[[level.round_end_custom_logic]]();
|
|
}
|
|
|
|
players = GetPlayers();
|
|
|
|
// PORTIZ 7/27/16: now that no_end_game_check is being used more regularly, I was tempted to remove/change this because it seems to arbitrarily add
|
|
// the revival of last stand players on top of whatever mechanic toggled the bool in the first place. however, it doesn't seem to do harm, and I'd rather avoid
|
|
// affecting these core systems if possible. for example, is there badness if a round transitions/starts and ALL players are in last stand? this can be revisited if
|
|
// any specific bugs/exploits arise from it...
|
|
if( ( isdefined( level.no_end_game_check ) && level.no_end_game_check ) )
|
|
{
|
|
level thread last_stand_revive();
|
|
level thread spectators_respawn();
|
|
}
|
|
else if ( 1 != players.size )
|
|
{
|
|
level thread spectators_respawn();
|
|
//level thread last_stand_revive();
|
|
}
|
|
|
|
players = GetPlayers();
|
|
array::thread_all( players, &zm_pers_upgrades_system::round_end );
|
|
|
|
if ( int(level.round_number / 5) * 5 == level.round_number )
|
|
{
|
|
level clientfield::set( "round_complete_time", int( ( level.time - level.n_gameplay_start_time + 500 ) / 1000 ) );
|
|
level clientfield::set( "round_complete_num", level.round_number );
|
|
}
|
|
|
|
//
|
|
// Increase the zombie move speed
|
|
//level.zombie_move_speed = level.round_number * level.zombie_vars["zombie_move_speed_multiplier"];
|
|
|
|
if( level.gamedifficulty == 0 ) //easy
|
|
{
|
|
level.zombie_move_speed = level.round_number * level.zombie_vars["zombie_move_speed_multiplier_easy"];
|
|
}
|
|
else //normal
|
|
{
|
|
level.zombie_move_speed = level.round_number * level.zombie_vars["zombie_move_speed_multiplier"];
|
|
}
|
|
|
|
set_round_number( 1 + get_round_number() );
|
|
SetRoundsPlayed( get_round_number() );
|
|
|
|
// Here's the difficulty increase over time area
|
|
//level.zombie_vars["zombie_spawn_delay"] = get_zombie_spawn_delay( level.round_number );
|
|
level.zombie_vars["zombie_spawn_delay"] = [[level.func_get_zombie_spawn_delay]]( get_round_number() );
|
|
|
|
// round_text( &"ZOMBIE_ROUND_END" );
|
|
|
|
matchUTCTime = GetUTC();
|
|
|
|
players = GetPlayers(); // delay in round_over allows a player that leaves during that time to remain in the players array - leading to round based SRES. Bad.
|
|
foreach(player in players)
|
|
{
|
|
if ( level.curr_gametype_affects_rank && get_round_number() > (3 + level.start_round) )
|
|
{
|
|
player zm_stats::add_client_stat( "weighted_rounds_played",get_round_number() );
|
|
}
|
|
player zm_stats::set_global_stat( "rounds", get_round_number() );
|
|
|
|
// update the game played time
|
|
player zm_stats::update_playing_utc_time( matchUTCTime );
|
|
|
|
// Reset the health if necessary
|
|
player zm_perks::perk_set_max_health_if_jugg( "health_reboot", true, true );
|
|
|
|
//XP event stuff
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
player.number_revives_per_round[i] = 0;
|
|
}
|
|
|
|
if ( IsAlive( player ) && player.sessionstate != "spectator" && !( isdefined( level.skip_alive_at_round_end_xp ) && level.skip_alive_at_round_end_xp ) )
|
|
{
|
|
player zm_stats::increment_challenge_stat( "SURVIVALIST_SURVIVE_ROUNDS" );
|
|
|
|
score_number = get_round_number() - 1;
|
|
if ( score_number < 1 )
|
|
{
|
|
score_number = 1;
|
|
}
|
|
else if ( score_number > 20 )
|
|
{
|
|
score_number = 20;
|
|
}
|
|
scoreevents::processScoreEvent( ("alive_at_round_end_" + score_number), player );
|
|
}
|
|
}
|
|
|
|
if( isdefined( level.check_quickrevive_hotjoin ) )
|
|
{
|
|
[[ level.check_quickrevive_hotjoin ]]();
|
|
}
|
|
|
|
level.round_number = get_round_number();
|
|
|
|
level round_over();
|
|
|
|
level notify( "between_round_over" );
|
|
|
|
level.skip_alive_at_round_end_xp = false;
|
|
|
|
restart = false;
|
|
}
|
|
}
|
|
|
|
|
|
function award_grenades_for_survivors()
|
|
{
|
|
players = GetPlayers();
|
|
|
|
for (i = 0; i < players.size; i++)
|
|
{
|
|
if (!players[i].is_zombie && !( isdefined( players[i].altbody ) && players[i].altbody ) && !players[i] laststand::player_is_in_laststand() )
|
|
{
|
|
lethal_grenade = players[i] zm_utility::get_player_lethal_grenade();
|
|
if( !players[i] HasWeapon( lethal_grenade ) )
|
|
{
|
|
players[i] GiveWeapon( lethal_grenade );
|
|
players[i] SetWeaponAmmoClip( lethal_grenade, 0 );
|
|
}
|
|
|
|
frac = players[i] GetFractionMaxAmmo( lethal_grenade );
|
|
if ( frac < .25 )
|
|
{
|
|
players[i] SetWeaponAmmoClip( lethal_grenade, 2 );
|
|
}
|
|
else if ( frac < .5 )
|
|
{
|
|
players[i] SetWeaponAmmoClip( lethal_grenade, 3 );
|
|
}
|
|
else
|
|
{
|
|
players[i] SetWeaponAmmoClip( lethal_grenade, 4 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Calculate the correct spawn delay for the round number
|
|
function get_zombie_spawn_delay( n_round )
|
|
{
|
|
if ( n_round > 60 ) // Don't let this loop too many times
|
|
{
|
|
n_round = 60;
|
|
}
|
|
|
|
// Decay rate
|
|
n_multiplier = 0.95;
|
|
// Base delay
|
|
switch( level.players.size )
|
|
{
|
|
case 1:
|
|
n_delay = 2.0; // 0.95 == 0.1 @ round 60
|
|
break;
|
|
case 2:
|
|
n_delay = 1.5; // 0.95 == 0.1 @ round 54
|
|
break;
|
|
case 3:
|
|
n_delay = 0.89; // 0.95 == 0.1 @ round 60
|
|
break;
|
|
case 4:
|
|
n_delay = 0.67; // 0.95 == 0.1 @ round 60
|
|
break;
|
|
}
|
|
|
|
for( i=1; i<n_round; i++ )
|
|
{
|
|
n_delay *= n_multiplier;
|
|
|
|
if ( n_delay <= 0.1 )
|
|
{
|
|
n_delay = 0.1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return n_delay;
|
|
}
|
|
|
|
|
|
/#
|
|
function round_spawn_failsafe_debug()
|
|
{
|
|
level notify( "failsafe_debug_stop" );
|
|
level endon( "failsafe_debug_stop" );
|
|
|
|
start = GetTime();
|
|
level.chunk_time = 0;
|
|
|
|
while ( 1 )
|
|
{
|
|
level.failsafe_time = GetTime() - start;
|
|
|
|
if ( isdefined( self.lastchunk_destroy_time ) )
|
|
{
|
|
level.chunk_time = GetTime() - self.lastchunk_destroy_time;
|
|
}
|
|
util::wait_network_frame();
|
|
}
|
|
}
|
|
#/
|
|
|
|
/#
|
|
function print_zombie_counts()
|
|
{
|
|
while ( true )
|
|
{
|
|
if( GetDvarInt("zombiemode_debug_zombie_count") )
|
|
{
|
|
if( !isdefined( level.debug_zombie_count_hud ) )
|
|
{
|
|
level.debug_zombie_count_hud= NewDebugHudElem();
|
|
level.debug_zombie_count_hud.alignX = "right";
|
|
level.debug_zombie_count_hud.x = 100;
|
|
level.debug_zombie_count_hud.y = 10;
|
|
level.debug_zombie_count_hud SetText( "COUNTS" );
|
|
}
|
|
|
|
currentCount = zombie_utility::get_current_zombie_count();
|
|
number_to_kill = level.zombie_total;
|
|
level.debug_zombie_count_hud SetText( "ALIVE=" + currentCount + " / TOGO=" + number_to_kill );
|
|
//println( "ALIVE=" + currentCount + " / TOGO=" + number_to_kill );
|
|
}
|
|
else
|
|
{
|
|
if( isdefined( level.debug_zombie_count_hud ) )
|
|
{
|
|
level.debug_zombie_count_hud Destroy();
|
|
level.debug_zombie_count_hud = undefined;
|
|
}
|
|
}
|
|
|
|
wait( 0.1 );
|
|
}
|
|
}
|
|
#/
|
|
|
|
|
|
// Waits for the time and the ai to die
|
|
function round_wait()
|
|
{
|
|
level endon("restart_round");
|
|
/#
|
|
level endon( "kill_round" );
|
|
#/
|
|
|
|
/#
|
|
if (GetDvarInt( "zombie_rise_test") )
|
|
{
|
|
level waittill("forever"); // TESTING: don't advance rounds
|
|
}
|
|
#/
|
|
|
|
if ( cheat_enabled( 2 ) )
|
|
{
|
|
level waittill("forever");
|
|
}
|
|
|
|
/#
|
|
if ( GetDvarInt( "zombie_default_max" ) == 0 )
|
|
{
|
|
level waittill( "forever" );
|
|
}
|
|
#/
|
|
|
|
wait( 1 );
|
|
|
|
/#
|
|
level thread print_zombie_counts();
|
|
level thread sndMusicOnKillRound();
|
|
#/
|
|
|
|
while( 1 )
|
|
{
|
|
should_wait = ( zombie_utility::get_current_zombie_count() > 0 || level.zombie_total > 0 || level.intermission );
|
|
if( !should_wait )
|
|
{
|
|
level thread zm_audio::sndMusicSystem_PlayState( "round_end" );
|
|
return;
|
|
}
|
|
|
|
if( level flag::get( "end_round_wait" ) )
|
|
{
|
|
level thread zm_audio::sndMusicSystem_PlayState( "round_end" );
|
|
return;
|
|
}
|
|
wait( 1.0 );
|
|
}
|
|
}
|
|
//To make sure music plays when using debug to switch rounds
|
|
function sndMusicOnKillRound()
|
|
{
|
|
level endon( "end_of_round" );
|
|
|
|
level waittill( "kill_round" );
|
|
level thread zm_audio::sndMusicSystem_PlayState( "round_end" );
|
|
}
|
|
|
|
|
|
|
|
function zombify_player() // self = player
|
|
{
|
|
self zm_score::player_died_penalty();
|
|
|
|
self RecordPlayerDeathZombies();
|
|
|
|
if ( IsDefined( level.deathcard_spawn_func ) )
|
|
{
|
|
self [[level.deathcard_spawn_func]]();
|
|
}
|
|
|
|
if( isdefined( level.func_clone_plant_respawn ) && isdefined( self.s_clone_plant ) )
|
|
{
|
|
self [[level.func_clone_plant_respawn]]();
|
|
return;
|
|
}
|
|
|
|
if( !IsDefined( level.zombie_vars["zombify_player"] ) || !level.zombie_vars["zombify_player"] )
|
|
{
|
|
self thread spawnSpectator();
|
|
return;
|
|
}
|
|
|
|
self.ignoreme = true;
|
|
self.is_zombie = true;
|
|
self.zombification_time = GetTime();
|
|
|
|
self.team = level.zombie_team;
|
|
self notify( "zombified" );
|
|
|
|
if( IsDefined( self.revivetrigger ) )
|
|
{
|
|
self.revivetrigger Delete();
|
|
}
|
|
self.revivetrigger = undefined;
|
|
|
|
self setMoveSpeedScale( 0.3 );
|
|
self reviveplayer();
|
|
|
|
self TakeAllWeapons();
|
|
self DisableWeaponCycling();
|
|
self DisableOffhandWeapons();
|
|
|
|
self thread zombie_utility::zombie_eye_glow();
|
|
|
|
self thread playerzombie_player_damage();
|
|
self thread playerzombie_soundboard();
|
|
}
|
|
|
|
function playerzombie_player_damage()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
self thread playerzombie_infinite_health(); // manually keep regular health up
|
|
self.zombiehealth = level.zombie_health;
|
|
|
|
// enable PVP damage on this guy
|
|
// self EnablePvPDamage();
|
|
|
|
while( 1 )
|
|
{
|
|
self waittill( "damage", amount, attacker, directionVec, point, type );
|
|
|
|
if( !IsDefined( attacker ) || !IsPlayer( attacker ) )
|
|
{
|
|
{wait(.05);};
|
|
continue;
|
|
}
|
|
|
|
self.zombiehealth -= amount;
|
|
|
|
if( self.zombiehealth <= 0 )
|
|
{
|
|
// "down" the zombie
|
|
self thread playerzombie_downed_state();
|
|
self waittill( "playerzombie_downed_state_done" );
|
|
self.zombiehealth = level.zombie_health;
|
|
}
|
|
}
|
|
}
|
|
|
|
function playerzombie_downed_state()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
downTime = 15;
|
|
|
|
startTime = GetTime();
|
|
endTime = startTime +( downTime * 1000 );
|
|
|
|
self thread playerzombie_downed_hud();
|
|
|
|
self.playerzombie_soundboard_disable = true;
|
|
self thread zombie_utility::zombie_eye_glow_stop();
|
|
self DisableWeapons();
|
|
self AllowStand( false );
|
|
self AllowCrouch( false );
|
|
self AllowProne( true );
|
|
|
|
while( GetTime() < endTime )
|
|
{
|
|
{wait(.05);};
|
|
}
|
|
|
|
self.playerzombie_soundboard_disable = false;
|
|
self thread zombie_utility::zombie_eye_glow();
|
|
self EnableWeapons();
|
|
self AllowStand( true );
|
|
self AllowCrouch( false );
|
|
self AllowProne( false );
|
|
|
|
self notify( "playerzombie_downed_state_done" );
|
|
}
|
|
|
|
function playerzombie_downed_hud()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
text = NewClientHudElem( self );
|
|
text.alignX = "center";
|
|
text.alignY = "middle";
|
|
text.horzAlign = "user_center";
|
|
text.vertAlign = "user_bottom";
|
|
text.foreground = true;
|
|
text.font = "default";
|
|
text.fontScale = 1.8;
|
|
text.alpha = 0;
|
|
text.color = ( 1.0, 1.0, 1.0 );
|
|
text SetText( &"ZOMBIE_PLAYERZOMBIE_DOWNED" );
|
|
|
|
text.y = -113;
|
|
if( self IsSplitScreen() )
|
|
{
|
|
text.y = -137;
|
|
}
|
|
|
|
text FadeOverTime( 0.1 );
|
|
text.alpha = 1;
|
|
|
|
self waittill( "playerzombie_downed_state_done" );
|
|
|
|
text FadeOverTime( 0.1 );
|
|
text.alpha = 0;
|
|
}
|
|
|
|
function playerzombie_infinite_health()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
bighealth = 100000;
|
|
|
|
while( 1 )
|
|
{
|
|
if( self.health < bighealth )
|
|
{
|
|
self.health = bighealth;
|
|
}
|
|
|
|
wait( 0.1 );
|
|
}
|
|
}
|
|
|
|
function playerzombie_soundboard()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
self.playerzombie_soundboard_disable = false;
|
|
|
|
self.buttonpressed_use = false;
|
|
self.buttonpressed_attack = false;
|
|
self.buttonpressed_ads = false;
|
|
|
|
self.useSound_waitTime = 3 * 1000; // milliseconds
|
|
self.useSound_nextTime = GetTime();
|
|
useSound = "playerzombie_usebutton_sound";
|
|
|
|
self.attackSound_waitTime = 3 * 1000;
|
|
self.attackSound_nextTime = GetTime();
|
|
attackSound = "playerzombie_attackbutton_sound";
|
|
|
|
self.adsSound_waitTime = 3 * 1000;
|
|
self.adsSound_nextTime = GetTime();
|
|
adsSound = "playerzombie_adsbutton_sound";
|
|
|
|
self.inputSound_nextTime = GetTime(); // don't want to be able to do all sounds at once
|
|
|
|
while( 1 )
|
|
{
|
|
if( self.playerzombie_soundboard_disable )
|
|
{
|
|
{wait(.05);};
|
|
continue;
|
|
}
|
|
|
|
if( self UseButtonPressed() )
|
|
{
|
|
if( self can_do_input( "use" ) )
|
|
{
|
|
self thread playerzombie_play_sound( useSound );
|
|
self thread playerzombie_waitfor_buttonrelease( "use" );
|
|
self.useSound_nextTime = GetTime() + self.useSound_waitTime;
|
|
}
|
|
}
|
|
else if( self AttackButtonPressed() )
|
|
{
|
|
if( self can_do_input( "attack" ) )
|
|
{
|
|
self thread playerzombie_play_sound( attackSound );
|
|
self thread playerzombie_waitfor_buttonrelease( "attack" );
|
|
self.attackSound_nextTime = GetTime() + self.attackSound_waitTime;
|
|
}
|
|
}
|
|
else if( self AdsButtonPressed() )
|
|
{
|
|
if( self can_do_input( "ads" ) )
|
|
{
|
|
self thread playerzombie_play_sound( adsSound );
|
|
self thread playerzombie_waitfor_buttonrelease( "ads" );
|
|
self.adsSound_nextTime = GetTime() + self.adsSound_waitTime;
|
|
}
|
|
}
|
|
|
|
{wait(.05);};
|
|
}
|
|
}
|
|
|
|
function can_do_input( inputType )
|
|
{
|
|
if( GetTime() < self.inputSound_nextTime )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
canDo = false;
|
|
|
|
switch( inputType )
|
|
{
|
|
case "use":
|
|
if( GetTime() >= self.useSound_nextTime && !self.buttonpressed_use )
|
|
{
|
|
canDo = true;
|
|
}
|
|
break;
|
|
|
|
case "attack":
|
|
if( GetTime() >= self.attackSound_nextTime && !self.buttonpressed_attack )
|
|
{
|
|
canDo = true;
|
|
}
|
|
break;
|
|
|
|
case "ads":
|
|
if( GetTime() >= self.useSound_nextTime && !self.buttonpressed_ads )
|
|
{
|
|
canDo = true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERTMSG( "can_do_input(): didn't recognize inputType of " + inputType );
|
|
break;
|
|
}
|
|
|
|
return canDo;
|
|
}
|
|
|
|
function playerzombie_play_sound( alias )
|
|
{
|
|
self zm_utility::play_sound_on_ent( alias );
|
|
}
|
|
|
|
function playerzombie_waitfor_buttonrelease( inputType )
|
|
{
|
|
if( inputType != "use" && inputType != "attack" && inputType != "ads" )
|
|
{
|
|
ASSERTMSG( "playerzombie_waitfor_buttonrelease(): inputType of " + inputType + " is not recognized." );
|
|
return;
|
|
}
|
|
|
|
notifyString = "waitfor_buttonrelease_" + inputType;
|
|
self notify( notifyString );
|
|
self endon( notifyString );
|
|
|
|
if( inputType == "use" )
|
|
{
|
|
self.buttonpressed_use = true;
|
|
while( self UseButtonPressed() )
|
|
{
|
|
{wait(.05);};
|
|
}
|
|
self.buttonpressed_use = false;
|
|
}
|
|
|
|
else if( inputType == "attack" )
|
|
{
|
|
self.buttonpressed_attack = true;
|
|
while( self AttackButtonPressed() )
|
|
{
|
|
{wait(.05);};
|
|
}
|
|
self.buttonpressed_attack = false;
|
|
}
|
|
|
|
else if( inputType == "ads" )
|
|
{
|
|
self.buttonpressed_ads = true;
|
|
while( self AdsButtonPressed() )
|
|
{
|
|
{wait(.05);};
|
|
}
|
|
self.buttonpressed_ads = false;
|
|
}
|
|
}
|
|
|
|
function remove_ignore_attacker()
|
|
{
|
|
self notify( "new_ignore_attacker" );
|
|
self endon( "new_ignore_attacker" );
|
|
self endon( "disconnect" );
|
|
|
|
if( !isDefined( level.ignore_enemy_timer ) )
|
|
{
|
|
level.ignore_enemy_timer = 0.4;
|
|
}
|
|
|
|
wait( level.ignore_enemy_timer );
|
|
|
|
self.ignoreAttacker = undefined;
|
|
}
|
|
|
|
function player_damage_override_cheat( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime )
|
|
{
|
|
player_damage_override( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime );
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// player_damage_override
|
|
// MUST return the value of the damage override
|
|
//
|
|
// MM (08/10/09) - Removed calls to PlayerDamageWrapper because it's always called in
|
|
// Callback_PlayerDamage now. We just need to return the damage.
|
|
//
|
|
function player_damage_override( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime )
|
|
{
|
|
iDamage = self check_player_damage_callbacks( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime );
|
|
|
|
if( self.scene_takedamage === false )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( IsDefined( eAttacker ) && ( isdefined( eAttacker.b_aat_fire_works_weapon ) && eAttacker.b_aat_fire_works_weapon ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( ( isdefined( self.use_adjusted_grenade_damage ) && self.use_adjusted_grenade_damage ) )
|
|
{
|
|
self.use_adjusted_grenade_damage = undefined;
|
|
if( ( self.health > iDamage ) )
|
|
{
|
|
return iDamage;
|
|
}
|
|
}
|
|
|
|
if ( !iDamage )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// WW (8/20/10) - Sledgehammer fix for Issue 43492. This should stop the player from taking any damage while in laststand
|
|
if( self laststand::player_is_in_laststand() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( isDefined( eInflictor ) )
|
|
{
|
|
if ( ( isdefined( eInflictor.water_damage ) && eInflictor.water_damage ) )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ( isDefined( eAttacker ) )
|
|
{
|
|
if( ( eAttacker.owner === self ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( isDefined( self.ignoreAttacker ) && self.ignoreAttacker == eAttacker )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// AR (5/30/12) - Stop Zombie players from damaging other Zombie players
|
|
if ( ( isdefined( self.is_zombie ) && self.is_zombie ) && ( isdefined( eAttacker.is_zombie ) && eAttacker.is_zombie ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( (isDefined( eAttacker.is_zombie ) && eAttacker.is_zombie) )
|
|
{
|
|
self.ignoreAttacker = eAttacker;
|
|
self thread remove_ignore_attacker();
|
|
|
|
if ( isdefined( eAttacker.custom_damage_func ) )
|
|
{
|
|
iDamage = eAttacker [[ eAttacker.custom_damage_func ]]( self );
|
|
}
|
|
}
|
|
|
|
eAttacker notify( "hit_player" );
|
|
|
|
if ( isdefined( eAttacker ) && isdefined( eAttacker.func_mod_damage_override ) )
|
|
{
|
|
sMeansOfDeath = eAttacker [[ eAttacker.func_mod_damage_override ]]( eInflictor, sMeansOfDeath, weapon );
|
|
}
|
|
|
|
if( sMeansOfDeath != "MOD_FALLING" )
|
|
{
|
|
self thread playSwipeSound( sMeansOfDeath, eattacker );
|
|
if( ( isdefined( eattacker.is_zombie ) && eattacker.is_zombie ) || IsPlayer(eAttacker) )
|
|
self PlayRumbleOnEntity( "damage_heavy" );
|
|
|
|
if( ( isdefined( eattacker.is_zombie ) && eattacker.is_zombie ) )
|
|
{
|
|
self zm_audio::create_and_play_dialog( "general", "attacked" );
|
|
}
|
|
|
|
canExert = true;
|
|
|
|
if ( ( isdefined( level.pers_upgrade_flopper ) && level.pers_upgrade_flopper ) )
|
|
{
|
|
// If the player has persistent flopper power, then no exert on explosion
|
|
if ( ( isdefined( self.pers_upgrades_awarded[ "flopper" ] ) && self.pers_upgrades_awarded[ "flopper" ] ) )
|
|
{
|
|
canExert = ( sMeansOfDeath != "MOD_PROJECTILE_SPLASH" && sMeansOfDeath != "MOD_GRENADE" && sMeansOfDeath != "MOD_GRENADE_SPLASH" );
|
|
}
|
|
}
|
|
|
|
if ( ( isdefined( canExert ) && canExert ) )
|
|
{
|
|
if(RandomIntRange(0,1) == 0 )
|
|
{
|
|
self thread zm_audio::playerExert( "hitmed" );
|
|
//self thread zm_audio::create_and_play_dialog( "general", "hitmed" );
|
|
}
|
|
else
|
|
{
|
|
self thread zm_audio::playerExert( "hitlrg" );
|
|
//self thread zm_audio::create_and_play_dialog( "general", "hitlrg" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Audio(RG:2/1/2016) adding underwater drowning exert.
|
|
if ( isDefined( sMeansOfDeath) && sMeansOfDeath == "MOD_DROWN")
|
|
{
|
|
self thread zm_audio::playerExert( "drowning", true );
|
|
self.voxDrowning = true;
|
|
}
|
|
|
|
if( isdefined( level.perk_damage_override ) )
|
|
{
|
|
foreach( func in level.perk_damage_override )
|
|
{
|
|
n_damage = self [[ func ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime );
|
|
if( isdefined( n_damage ) )
|
|
{
|
|
iDamage = n_damage;
|
|
}
|
|
}
|
|
}
|
|
finalDamage = iDamage;
|
|
|
|
|
|
// claymores and freezegun shatters, like bouncing betties, harm no players
|
|
if ( zm_utility::is_placeable_mine( weapon ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( isDefined( self.player_damage_override ) )
|
|
{
|
|
self thread [[ self.player_damage_override ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime );
|
|
}
|
|
|
|
// exploding quads should not kill player
|
|
if ( IsDefined( eInflictor ) && IsDefined( eInflictor.archetype ) && eInflictor.archetype == "zombie_quad" )
|
|
{
|
|
if ( sMeansOfDeath == "MOD_EXPLOSIVE" )
|
|
{
|
|
if ( self.health > 75 )
|
|
{
|
|
return 75;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Players can't die from cooked grenade if trhey have the bgb Danger Closet
|
|
if ( sMeansOfDeath == "MOD_SUICIDE" && self bgb::is_enabled( "zm_bgb_danger_closest" ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( sMeansOfDeath == "MOD_PROJECTILE" || sMeansOfDeath == "MOD_PROJECTILE_SPLASH" || sMeansOfDeath == "MOD_GRENADE" || sMeansOfDeath == "MOD_GRENADE_SPLASH" || sMeansOfDeath == "MOD_EXPLOSIVE" )
|
|
{
|
|
if( self bgb::is_enabled( "zm_bgb_danger_closest" ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// player explosive splash damage (caps explosive damage), fixes raygun damage being fatal (or grenades) when damaging yourself
|
|
if ( !( isdefined( self.is_zombie ) && self.is_zombie ) )
|
|
{
|
|
// Don't do this for projectile damage coming from zombies
|
|
if ( !isdefined( eAttacker ) || ( !( isdefined( eAttacker.is_zombie ) && eAttacker.is_zombie ) && !( isdefined( eAttacker.b_override_explosive_damage_cap ) && eAttacker.b_override_explosive_damage_cap ) ) )
|
|
{
|
|
// Only do it for ray gun
|
|
if( isdefined(weapon.name) && ((weapon.name == "ray_gun") || ( weapon.name == "ray_gun_upgraded" )) )
|
|
{
|
|
// Clamp it, we don't want to increase the damage from player raygun splash damage or grenade splash damage
|
|
// Don't create more damage than we are trying to apply
|
|
if ( ( self.health > 25 ) && ( iDamage > 25 ) )
|
|
{
|
|
return 25;
|
|
}
|
|
}
|
|
else if ( ( self.health > 75 ) && ( iDamage > 75 ) )
|
|
{
|
|
return 75;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( iDamage < self.health )
|
|
{
|
|
if ( IsDefined( eAttacker ) )
|
|
{
|
|
if( IsDefined( level.custom_kill_damaged_VO ) )
|
|
{
|
|
eAttacker thread [[ level.custom_kill_damaged_VO ]]( self );
|
|
}
|
|
else
|
|
{
|
|
eAttacker.sound_damage_player = self;
|
|
}
|
|
|
|
if( ( isdefined( eAttacker.missingLegs ) && eAttacker.missingLegs ) )
|
|
{
|
|
self zm_audio::create_and_play_dialog( "general", "crawl_hit" );
|
|
}
|
|
}
|
|
|
|
// MM (08/10/09)
|
|
return finalDamage;
|
|
}
|
|
|
|
//player died
|
|
if( isdefined( eAttacker ) )
|
|
{
|
|
if(isDefined(eAttacker.animname) && eAttacker.animname == "zombie_dog")
|
|
{
|
|
self zm_stats::increment_client_stat( "killed_by_zdog" );
|
|
self zm_stats::increment_player_stat( "killed_by_zdog" );
|
|
}
|
|
else if(( isdefined( eAttacker.is_avogadro ) && eAttacker.is_avogadro ))
|
|
{
|
|
self zm_stats::increment_client_stat( "killed_by_avogadro", false );
|
|
self zm_stats::increment_player_stat( "killed_by_avogadro" );
|
|
}
|
|
}
|
|
|
|
self thread clear_path_timers();
|
|
|
|
if( level.intermission )
|
|
{
|
|
level waittill( "forever" );
|
|
}
|
|
|
|
// AR (3/7/12) - Keep track of which player killed player in Zombify modes like Cleansed / Turned
|
|
// Confirmed with Alex
|
|
if ( level.scr_zm_ui_gametype == "zcleansed" && iDamage > 0 )
|
|
{
|
|
if ( IsDefined( eAttacker ) && IsPlayer( eAttacker ) && eAttacker.team != self.team && ( ( !( isdefined( self.laststand ) && self.laststand ) && !self laststand::player_is_in_laststand() ) || !IsDefined( self.last_player_attacker ) ) )
|
|
{
|
|
// Restore Health To Zombie Player
|
|
//--------------------------------
|
|
if ( IsDefined( eAttacker.maxhealth ) && ( isdefined( eAttacker.is_zombie ) && eAttacker.is_zombie ) )
|
|
{
|
|
eAttacker.health = eAttacker.maxhealth;
|
|
}
|
|
|
|
//self.last_player_attacker = eAttacker;
|
|
|
|
if ( IsDefined( level.player_kills_player ) )
|
|
{
|
|
self thread [[ level.player_kills_player]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( self.lives > 0 && self HasPerk( "specialty_whoswho" ) )
|
|
{
|
|
self.lives--;
|
|
if ( IsDefined( level.whoswho_laststand_func ) )
|
|
{
|
|
self thread [[ level.whoswho_laststand_func]]();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
players = GetPlayers();
|
|
count = 0;
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
if( players[i] == self || players[i].is_zombie || players[i] laststand::player_is_in_laststand() || players[i].sessionstate == "spectator" )
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if( count < players.size || (isDefined(level._game_module_game_end_check) && ![[level._game_module_game_end_check]]()) )
|
|
{
|
|
if ( IsDefined( self.lives ) && self.lives > 0 && ( isdefined( level.force_solo_quick_revive ) && level.force_solo_quick_revive ) && self HasPerk( "specialty_quickrevive" ) )
|
|
{
|
|
self thread wait_and_revive();
|
|
}
|
|
|
|
// MM (08/10/09)
|
|
return finalDamage;
|
|
}
|
|
|
|
// PORTIZ 7/27/16: added level.no_end_game_check here, because if it's true by this point, this function will end up returning finalDamage anyway. additionally,
|
|
// no_end_game_check has been updated to support incrementing/decrementing, which makes it more robust than a single level.check_end_solo_game_override as more
|
|
// mechanics are introduced that require solo players to go into last stand instead of losing the game immediately
|
|
if ( players.size == 1 && level flag::get( "solo_game" ) )
|
|
{
|
|
if ( ( isdefined( level.no_end_game_check ) && level.no_end_game_check ) || ( isdefined( level.check_end_solo_game_override ) && [[level.check_end_solo_game_override]]() ) )
|
|
{
|
|
return finalDamage;
|
|
}
|
|
else if ( self.lives == 0 || !self HasPerk( "specialty_quickrevive" ) )
|
|
{
|
|
self.intermission = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// WW (01/05/11): When a two players enter a system link game and the client drops the host will be treated as if it was a solo game
|
|
// when it wasn't. This led to SREs about undefined and int being compared on death (self.lives was never defined on the host). While
|
|
// adding the check for the solo game flag we found that we would have to create a complex OR inside of the if check below. By breaking
|
|
// the conditions out in to their own variables we keep the complexity without making it look like a mess.
|
|
solo_death = ( players.size == 1 && level flag::get( "solo_game" ) && ( self.lives == 0 || !self HasPerk("specialty_quickrevive") ) ); // there is only one player AND the flag is set AND self.lives equals 0
|
|
non_solo_death = ( ( count > 1 || ( players.size == 1 && !level flag::get( "solo_game" ) ) ) /*&& !level.is_zombie_level*/ ); // the player size is greater than one OR ( players.size equals 1 AND solo flag isn't set ) AND not a zombify game level
|
|
if ( (solo_death || non_solo_death) && !( isdefined( level.no_end_game_check ) && level.no_end_game_check ) ) // if only one player on their last life or any game that started with more than one player
|
|
{
|
|
level notify("stop_suicide_trigger");
|
|
self AllowProne( true ); //just in case
|
|
self thread zm_laststand::PlayerLastStand( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime );
|
|
if( !isdefined( vDir ) )
|
|
{
|
|
vDir = ( 1.0, 0.0, 0.0 );
|
|
}
|
|
self FakeDamageFrom(vDir);
|
|
|
|
level notify("last_player_died");
|
|
if ( isdefined(level.custom_player_fake_death) )
|
|
self thread [[level.custom_player_fake_death]](vDir, sMeansOfDeath);
|
|
else
|
|
self thread player_fake_death();
|
|
}
|
|
|
|
if( count == players.size && !( isdefined( level.no_end_game_check ) && level.no_end_game_check ) )
|
|
{
|
|
if ( players.size == 1 && level flag::get( "solo_game" ))
|
|
{
|
|
if ( self.lives == 0 || !self HasPerk("specialty_quickrevive") ) // && !self laststand::player_is_in_laststand()
|
|
{
|
|
self.lives = 0;
|
|
level notify("pre_end_game");
|
|
util::wait_network_frame();
|
|
if(level flag::get("dog_round"))
|
|
{
|
|
increment_dog_round_stat( "lost" );
|
|
|
|
}
|
|
level notify( "end_game" );
|
|
}
|
|
else
|
|
{
|
|
return finalDamage;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
level notify("pre_end_game");
|
|
util::wait_network_frame();
|
|
if(level flag::get("dog_round"))
|
|
{
|
|
increment_dog_round_stat( "lost" );
|
|
|
|
}
|
|
level notify( "end_game" );
|
|
}
|
|
return 0; // MM (09/16/09) Need to return something
|
|
}
|
|
else
|
|
{
|
|
// MM (08/10/09)
|
|
|
|
surface = "flesh";
|
|
|
|
return finalDamage;
|
|
}
|
|
}
|
|
|
|
function clear_path_timers()
|
|
{
|
|
zombies = GetAITeamArray( level.zombie_team );
|
|
foreach( zombie in zombies )
|
|
{
|
|
if ( isdefined( zombie.favoriteenemy ) && ( zombie.favoriteenemy == self ) )
|
|
{
|
|
zombie.zombie_path_timer = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function check_player_damage_callbacks( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime )
|
|
{
|
|
if ( !isdefined( level.player_damage_callbacks ) )
|
|
{
|
|
return iDamage;
|
|
}
|
|
|
|
for ( i = 0; i < level.player_damage_callbacks.size; i++ )
|
|
{
|
|
newDamage = self [[ level.player_damage_callbacks[i] ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime );
|
|
if ( -1 != newDamage )
|
|
{
|
|
return newDamage;
|
|
}
|
|
}
|
|
|
|
return iDamage;
|
|
}
|
|
|
|
|
|
function register_player_damage_callback( func )
|
|
{
|
|
if ( !isdefined( level.player_damage_callbacks ) )
|
|
{
|
|
level.player_damage_callbacks = [];
|
|
}
|
|
|
|
level.player_damage_callbacks[level.player_damage_callbacks.size] = func;
|
|
}
|
|
|
|
|
|
function wait_and_revive()
|
|
{
|
|
|
|
self endon( "remote_revive" );
|
|
level flag::set( "wait_and_revive" );
|
|
level.wait_and_revive = true;
|
|
|
|
if ( isdefined( self.waiting_to_revive ) && self.waiting_to_revive == true )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Grab the perks if we have the player persistent ability "perk lose"
|
|
if( ( isdefined( self.pers_upgrades_awarded["perk_lose"] ) && self.pers_upgrades_awarded["perk_lose"] ) )
|
|
{
|
|
self zm_pers_upgrades_functions::pers_upgrade_perk_lose_save();
|
|
}
|
|
|
|
self.waiting_to_revive = true;
|
|
self.lives--;
|
|
|
|
if ( isdefined( level.exit_level_func ) )
|
|
{
|
|
self thread [[ level.exit_level_func ]]();
|
|
}
|
|
else
|
|
{
|
|
if ( GetPlayers().size == 1 )
|
|
{
|
|
player = GetPlayers()[0];
|
|
level.move_away_points = PositionQuery_Source_Navigation( player.origin, 12*40, 12*80, 120, 20 );
|
|
if ( !isdefined( level.move_away_points ) )
|
|
{
|
|
level.move_away_points = PositionQuery_Source_Navigation( player.last_valid_position, 12*40, 12*80, 120, 20 );
|
|
}
|
|
}
|
|
}
|
|
|
|
solo_revive_time = 10.0;
|
|
|
|
name = level.player_name_directive[self GetEntityNumber()];
|
|
self.revive_hud setText( &"ZOMBIE_REVIVING_SOLO", name );
|
|
self laststand::revive_hud_show_n_fade( solo_revive_time );
|
|
|
|
level flag::wait_till_timeout( solo_revive_time, "instant_revive" );
|
|
|
|
if ( level flag::get( "instant_revive" ) )
|
|
{
|
|
self laststand::revive_hud_show_n_fade( 1.0 );
|
|
}
|
|
|
|
level flag::clear( "wait_and_revive" );
|
|
level.wait_and_revive = false;
|
|
|
|
self zm_laststand::auto_revive( self );
|
|
self.waiting_to_revive = false;
|
|
|
|
// Give player his perks back if he has the "perk_lose" persistent ability
|
|
if( ( isdefined( self.pers_upgrades_awarded["perk_lose"] ) && self.pers_upgrades_awarded["perk_lose"] ) )
|
|
{
|
|
self thread zm_pers_upgrades_functions::pers_upgrade_perk_lose_restore();
|
|
}
|
|
}
|
|
|
|
function register_vehicle_damage_callback( func )
|
|
{
|
|
if( !IsDefined( level.vehicle_damage_callbacks ) )
|
|
{
|
|
level.vehicle_damage_callbacks = [];
|
|
}
|
|
|
|
level.vehicle_damage_callbacks[level.vehicle_damage_callbacks.size] = func;
|
|
}
|
|
|
|
function vehicle_damage_override( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
|
|
{
|
|
//apply damage modifiers on the vehicle
|
|
if( IsDefined( level.vehicle_damage_callbacks ) )
|
|
{
|
|
for( i = 0; i < level.vehicle_damage_callbacks.size; i++ )
|
|
{
|
|
iDamage = self [[ level.vehicle_damage_callbacks[i] ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal );
|
|
}
|
|
}
|
|
|
|
//TODO Sabarish: Move code from globallogic to here to be more consistent with other zombie damage functions
|
|
self globallogic_vehicle::Callback_VehicleDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal );
|
|
}
|
|
|
|
//
|
|
// MUST return the value of the damage override
|
|
//
|
|
function actor_damage_override( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, psOffsetTime, boneIndex, surfaceType )
|
|
{
|
|
// skip conditions
|
|
if ( !isdefined( self ) || !isdefined( attacker ) )
|
|
return damage;
|
|
|
|
damage = bgb::actor_damage_override( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, psOffsetTime, boneIndex, surfaceType );
|
|
|
|
damage = self check_actor_damage_callbacks( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, psOffsetTime, boneIndex, surfaceType );
|
|
|
|
self.knuckles_extinguish_flames = (weapon.name == "tazer_knuckles");
|
|
|
|
if ( isdefined( attacker.animname ) && attacker.animname == "quad_zombie" )
|
|
{
|
|
if ( isdefined( self.animname ) && self.animname == "quad_zombie" )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ( isdefined( self.killby_interdimensional_gun_hole ) )
|
|
{
|
|
return damage;
|
|
}
|
|
else if ( isdefined( self.interdimensional_gun_kill ) )
|
|
{
|
|
if ( isdefined( self.idgun_damage_cb ) )
|
|
{
|
|
self [[ self.idgun_damage_cb ]]( inflictor, attacker );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
if ( isdefined( weapon ) )
|
|
{
|
|
if( is_idgun_damage( weapon ) && ( !IsDefined( meansofdeath ) || meansofdeath != "MOD_EXPLOSIVE" ) )
|
|
{
|
|
if( !( self.archetype === "margwa" ) && !( self.archetype === "mechz" ))
|
|
{
|
|
self.damageOrigin = vpoint;
|
|
self.allowdeath = false;
|
|
self.magic_bullet_shield = true;
|
|
self.interdimensional_gun_kill = true;
|
|
self.interdimensional_gun_weapon = weapon;
|
|
self.interdimensional_gun_attacker = attacker;
|
|
|
|
if ( isdefined( inflictor ) )
|
|
{
|
|
self.interdimensional_gun_inflictor = inflictor;
|
|
}
|
|
else
|
|
{
|
|
self.interdimensional_gun_inflictor = attacker;
|
|
}
|
|
}
|
|
|
|
if ( isdefined( self.idgun_damage_cb ) )
|
|
{
|
|
self [[ self.idgun_damage_cb ]]( inflictor, attacker );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
attacker thread zm_audio::sndPlayerHitAlert( self, meansofdeath, inflictor, weapon );
|
|
|
|
if ( !isplayer( attacker ) && isdefined( self.non_attacker_func ) )
|
|
{
|
|
if(( isdefined( self.non_attack_func_takes_attacker ) && self.non_attack_func_takes_attacker ))
|
|
{
|
|
return self [[ self.non_attacker_func ]]( damage, weapon, attacker );
|
|
}
|
|
else
|
|
{
|
|
return self [[ self.non_attacker_func ]]( damage, weapon );
|
|
}
|
|
}
|
|
|
|
if ( IsDefined( attacker ) && IsAI( attacker ) )
|
|
{
|
|
// AI do not do melee damage to teammates
|
|
if( self.team == attacker.team && meansofdeath == "MOD_MELEE" )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ( attacker.classname == "script_vehicle" && isDefined( attacker.owner ) )
|
|
{
|
|
attacker = attacker.owner;
|
|
}
|
|
|
|
if ( !isdefined( damage ) || !isdefined( meansofdeath ) )
|
|
{
|
|
return damage;
|
|
}
|
|
|
|
if ( meansofdeath == "" )
|
|
{
|
|
return damage;
|
|
}
|
|
|
|
// This is the AI system's override damage callback, it must come last!
|
|
if ( IsDefined( self.aiOverrideDamage ) )
|
|
{
|
|
for ( index = 0; index < self.aiOverrideDamage.size; index++ )
|
|
{
|
|
damageCallback = self.aiOverrideDamage[index];
|
|
damage = self [[damageCallback]]( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, psOffsetTime, boneIndex, undefined );
|
|
}
|
|
if ( damage < 1 )
|
|
return 0;
|
|
|
|
damage = int( damage + 0.5 );
|
|
}
|
|
|
|
old_damage = damage;
|
|
final_damage = damage;
|
|
|
|
if ( IsDefined( self.actor_damage_func ) )
|
|
{
|
|
final_damage = [[ self.actor_damage_func ]]( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, psOffsetTime, boneIndex );
|
|
}
|
|
|
|
// debug
|
|
/#
|
|
if ( GetDvarInt( "scr_perkdebug") )
|
|
println( "Perk/> Damage Factor: " + final_damage/old_damage + " - Pre Damage: " + old_damage + " - Post Damage: " + final_damage );
|
|
#/
|
|
|
|
if ( ( isdefined( self.in_water ) && self.in_water ) )
|
|
{
|
|
if ( int( final_damage ) >= self.health )
|
|
{
|
|
self.water_damage = true;
|
|
}
|
|
}
|
|
|
|
//modifier for the sword in ZOD colliding with zombies
|
|
if ( IsDefined( inflictor ) && IsDefined( inflictor.archetype ) && inflictor.archetype == "glaive" )
|
|
{
|
|
if( meansofdeath == "MOD_CRUSH" )
|
|
{
|
|
if ( ( IsDefined( inflictor.enemy ) && inflictor.enemy != self ) || ( isdefined( inflictor._glaive_must_return_to_owner ) && inflictor._glaive_must_return_to_owner ) )
|
|
{
|
|
if ( IsDefined( self.archetype ) && self.archetype != "margwa" )
|
|
{
|
|
final_damage += self.health;
|
|
if ( IsActor( self ) )
|
|
{
|
|
self zombie_utility::gib_random_parts();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( isdefined( inflictor ) && isPlayer( attacker ) && attacker == inflictor )
|
|
{
|
|
if ( meansofdeath == "MOD_HEAD_SHOT" || meansofdeath == "MOD_PISTOL_BULLET" || meansofdeath == "MOD_RIFLE_BULLET" )
|
|
{
|
|
attacker.hits++;
|
|
}
|
|
}
|
|
|
|
if ( ( isdefined( level.headshots_only ) && level.headshots_only ) && isDefined( attacker ) && isplayer( attacker ) )
|
|
{
|
|
if ( meansofdeath == "MOD_MELEE" && ( sHitLoc == "head" || sHitLoc == "helmet" ) )
|
|
{
|
|
return int( final_damage );
|
|
}
|
|
if ( zm_utility::is_explosive_damage( meansofdeath ) )
|
|
{
|
|
return int( final_damage );
|
|
}
|
|
else if ( !zm_utility::is_headshot( weapon, sHitLoc, meansofdeath ) )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return int( final_damage );
|
|
}
|
|
|
|
function check_actor_damage_callbacks( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, psOffsetTime, boneIndex, surfaceType )
|
|
{
|
|
if ( !isdefined( level.actor_damage_callbacks ) )
|
|
{
|
|
return damage;
|
|
}
|
|
|
|
for ( i = 0; i < level.actor_damage_callbacks.size; i++ )
|
|
{
|
|
newDamage = self [[ level.actor_damage_callbacks[i] ]]( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, psOffsetTime, boneIndex, surfaceType );
|
|
if ( -1 != newDamage )
|
|
{
|
|
return newDamage;
|
|
}
|
|
}
|
|
|
|
return damage;
|
|
}
|
|
|
|
|
|
function register_actor_damage_callback( func )
|
|
{
|
|
if ( !isdefined( level.actor_damage_callbacks ) )
|
|
{
|
|
level.actor_damage_callbacks = [];
|
|
}
|
|
|
|
level.actor_damage_callbacks[level.actor_damage_callbacks.size] = func;
|
|
}
|
|
|
|
|
|
|
|
function actor_damage_override_wrapper( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, modelIndex, surfaceType, vSurfaceNormal )
|
|
{
|
|
damage_override = self actor_damage_override( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, psOffsetTime, boneIndex, surfaceType );
|
|
willBeKilled = ( self.health - damage_override ) <= 0;
|
|
if( isdefined( level.zombie_damage_override_callbacks ) )
|
|
{
|
|
foreach( func_override in level.zombie_damage_override_callbacks )
|
|
{
|
|
self thread [[ func_override ]]( willBeKilled, inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, psOffsetTime, boneIndex, surfaceType );
|
|
}
|
|
}
|
|
bb::logdamage( attacker, self, weapon, damage_override, meansofdeath, shitloc, willBeKilled, willBeKilled );
|
|
if ( !willBeKilled || !( isdefined( self.dont_die_on_me ) && self.dont_die_on_me ) )
|
|
{
|
|
self finishActorDamage( inflictor, attacker, damage_override, flags, meansofdeath, weapon, vpoint, vdir, sHitLoc, vDamageOrigin, psOffsetTime, boneIndex, surfaceType, vSurfaceNormal );
|
|
}
|
|
}
|
|
|
|
function register_zombie_damage_override_callback( func )
|
|
{
|
|
if(!isdefined(level.zombie_damage_override_callbacks))level.zombie_damage_override_callbacks=[];
|
|
|
|
if ( !isdefined( level.zombie_damage_override_callbacks ) ) level.zombie_damage_override_callbacks = []; else if ( !IsArray( level.zombie_damage_override_callbacks ) ) level.zombie_damage_override_callbacks = array( level.zombie_damage_override_callbacks ); level.zombie_damage_override_callbacks[level.zombie_damage_override_callbacks.size]=func;;
|
|
}
|
|
|
|
function actor_killed_override(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime)
|
|
{
|
|
if ( game["state"] == "postgame" )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( isai(attacker) && isDefined( attacker.script_owner ) )
|
|
{
|
|
// if the person who called the dogs in switched teams make sure they don't
|
|
// get penalized for the kill
|
|
if ( attacker.script_owner.team != self.team )
|
|
attacker = attacker.script_owner;
|
|
}
|
|
|
|
if( attacker.classname == "script_vehicle" && isDefined( attacker.owner ) )
|
|
{
|
|
attacker = attacker.owner;
|
|
}
|
|
|
|
if ( isdefined( attacker ) && isplayer( attacker ) )
|
|
{
|
|
multiplier = 1;
|
|
if( zm_utility::is_headshot( weapon, sHitLoc, sMeansOfDeath ) )
|
|
{
|
|
multiplier = 1.5;
|
|
}
|
|
|
|
type = undefined;
|
|
|
|
//MM (3/18/10) no animname check
|
|
if ( IsDefined(self.animname) )
|
|
{
|
|
switch( self.animname )
|
|
{
|
|
case "quad_zombie":
|
|
type = "quadkill";
|
|
break;
|
|
case "ape_zombie":
|
|
type = "apekill";
|
|
break;
|
|
case "zombie":
|
|
type = "zombiekill";
|
|
break;
|
|
case "zombie_dog":
|
|
type = "dogkill";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(( isdefined( self.is_ziplining ) && self.is_ziplining ))
|
|
{
|
|
self.deathanim = undefined;
|
|
}
|
|
|
|
if ( IsDefined( self.actor_killed_override ) )
|
|
{
|
|
self [[ self.actor_killed_override ]]( eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime );
|
|
}
|
|
|
|
if ( IsDefined( self.deathFunction ) )
|
|
{
|
|
self [[ self.deathFunction ]]( eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime );
|
|
}
|
|
}
|
|
|
|
|
|
function round_end_monitor()
|
|
{
|
|
while(1)
|
|
{
|
|
level waittill( "end_of_round" );
|
|
|
|
demo::bookmark( "zm_round_end", gettime(), undefined, undefined, 1 );
|
|
BBPostDemoStreamStatsForRound( level.round_number );
|
|
zm_utility::upload_zm_dash_counters();
|
|
|
|
{wait(.05);};
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function updateEndOfMatchCounters()
|
|
{
|
|
zm_utility::increment_zm_dash_counter( "end_per_game", 1 );
|
|
zm_utility::increment_zm_dash_counter( "end_per_player", level.players.size );
|
|
|
|
if( !( isdefined( level.dash_counter_round_reached_5 ) && level.dash_counter_round_reached_5 ) )
|
|
{
|
|
zm_utility::increment_zm_dash_counter( "end_less_5", 1 );
|
|
}
|
|
else
|
|
{
|
|
if( !( isdefined( level.dash_counter_round_reached_10 ) && level.dash_counter_round_reached_10 ) )
|
|
{
|
|
zm_utility::increment_zm_dash_counter( "end_reached_5_less_10", 1 );
|
|
}
|
|
else
|
|
{
|
|
zm_utility::increment_zm_dash_counter( "end_reached_10", 1 );
|
|
}
|
|
}
|
|
|
|
if( !zm_utility::is_solo_ranked_game() )
|
|
{
|
|
if( level.dash_counter_start_player_count != level.players.size )
|
|
{
|
|
zm_utility::increment_zm_dash_counter( "end_player_count_diff", 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
function end_game()
|
|
{
|
|
level waittill ( "end_game" );
|
|
|
|
check_end_game_intermission_delay();
|
|
|
|
/# println( "end_game TRIGGERED " ); #/
|
|
|
|
setmatchflag( "game_ended", 1 );
|
|
|
|
level clientfield::set("gameplay_started", 0);
|
|
level clientfield::set("game_end_time", int( ( GetTime() - level.n_gameplay_start_time + 500 ) / 1000 ) );
|
|
|
|
util::clientnotify( "zesn" );
|
|
|
|
level thread zm_audio::sndMusicSystem_PlayState( "game_over" );
|
|
|
|
//AYERS: Turn off ANY last stand audio at the end of the game
|
|
players = GetPlayers();
|
|
for ( i = 0; i < players.size; i++ )
|
|
{
|
|
players[i] clientfield::set( "zmbLastStand", 0 );
|
|
}
|
|
|
|
for ( i = 0; i < players.size; i++ )
|
|
{
|
|
if ( players[i] laststand::player_is_in_laststand() )
|
|
{
|
|
players[i] RecordPlayerDeathZombies();
|
|
players[i] zm_stats::increment_player_stat( "deaths" );
|
|
players[i] zm_stats::increment_client_stat( "deaths" );
|
|
players[i] zm_pers_upgrades_functions::pers_upgrade_jugg_player_death_stat();
|
|
}
|
|
|
|
//clean up the revive text hud if it's active
|
|
if( isdefined( players[i].reviveTextHud ) )
|
|
{
|
|
players[i].reviveTextHud destroy();
|
|
}
|
|
}
|
|
|
|
StopAllRumbles();
|
|
|
|
level.intermission = true;
|
|
level.zombie_vars["zombie_powerup_insta_kill_time"] = 0;
|
|
level.zombie_vars["zombie_powerup_fire_sale_time"] = 0;
|
|
level.zombie_vars["zombie_powerup_double_points_time"] = 0;
|
|
wait 0.1;
|
|
|
|
game_over = [];
|
|
survived = [];
|
|
|
|
players = GetPlayers();
|
|
|
|
//disabled the ingame pause menu from opening after a game ends
|
|
setMatchFlag( "disableIngameMenu", 1 );
|
|
foreach( player in players )
|
|
{
|
|
player closeInGameMenu();
|
|
player CloseMenu( "StartMenu_Main" );
|
|
}
|
|
|
|
|
|
//AAR - set stat for each player (this will show the menu)
|
|
foreach( player in players )
|
|
{
|
|
player setDStat( "AfterActionReportStats", "lobbyPopup", "summary" );
|
|
}
|
|
|
|
if(!isDefined(level._supress_survived_screen))
|
|
{
|
|
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
game_over[i] = NewClientHudElem( players[i] );
|
|
survived[i] = NewClientHudElem( players[i] );
|
|
if ( IsDefined( level.custom_game_over_hud_elem ) )
|
|
{
|
|
[[ level.custom_game_over_hud_elem ]]( players[i], game_over[i], survived[i] );
|
|
}
|
|
else
|
|
{
|
|
game_over[i].alignX = "center";
|
|
game_over[i].alignY = "middle";
|
|
game_over[i].horzAlign = "center";
|
|
game_over[i].vertAlign = "middle";
|
|
game_over[i].y -= 130;
|
|
game_over[i].foreground = true;
|
|
game_over[i].fontScale = 3;
|
|
game_over[i].alpha = 0;
|
|
game_over[i].color = ( 1.0, 1.0, 1.0 );
|
|
game_over[i].hidewheninmenu = true;
|
|
game_over[i] SetText( &"ZOMBIE_GAME_OVER" );
|
|
|
|
game_over[i] FadeOverTime( 1 );
|
|
game_over[i].alpha = 1;
|
|
if ( players[i] isSplitScreen() )
|
|
{
|
|
game_over[i].fontScale = 2;
|
|
game_over[i].y += 40;
|
|
}
|
|
|
|
survived[i].alignX = "center";
|
|
survived[i].alignY = "middle";
|
|
survived[i].horzAlign = "center";
|
|
survived[i].vertAlign = "middle";
|
|
survived[i].y -= 100;
|
|
survived[i].foreground = true;
|
|
survived[i].fontScale = 2;
|
|
survived[i].alpha = 0;
|
|
survived[i].color = ( 1.0, 1.0, 1.0 );
|
|
survived[i].hidewheninmenu = true;
|
|
if ( players[i] isSplitScreen() )
|
|
{
|
|
survived[i].fontScale = 1.5;
|
|
survived[i].y += 40;
|
|
}
|
|
}
|
|
|
|
|
|
//OLD COUNT METHOD
|
|
if( level.round_number < 2 )
|
|
{
|
|
if( level.script == "zm_moon" )
|
|
{
|
|
if( !isdefined(level.left_nomans_land) )
|
|
{
|
|
nomanslandtime = level.nml_best_time;
|
|
player_survival_time = int( nomanslandtime/1000 );
|
|
player_survival_time_in_mins = zm::to_mins( player_survival_time );
|
|
survived[i] SetText( &"ZOMBIE_SURVIVED_NOMANS", player_survival_time_in_mins );
|
|
}
|
|
else if( level.left_nomans_land == 2 )
|
|
{
|
|
survived[i] SetText( &"ZOMBIE_SURVIVED_ROUND" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
survived[i] SetText( &"ZOMBIE_SURVIVED_ROUND" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
survived[i] SetText( &"ZOMBIE_SURVIVED_ROUNDS", level.round_number );
|
|
}
|
|
|
|
survived[i] FadeOverTime( 1 );
|
|
survived[i].alpha = 1;
|
|
}
|
|
}
|
|
|
|
|
|
//check to see if we are in a game module that wants to do something with PvP damage
|
|
if(isDefined(level.custom_end_screen))
|
|
{
|
|
level [[level.custom_end_screen]]();
|
|
}
|
|
|
|
for (i = 0; i < players.size; i++)
|
|
{
|
|
players[i] SetClientUIVisibilityFlag( "weapon_hud_visible", 0 );
|
|
players[i] SetClientMiniScoreboardHide( true );
|
|
//players[i] setDStat( "AfterActionReportStats", "lobbyPopup", "summary" );
|
|
|
|
players[i] notify( "report_bgb_consumption" );
|
|
|
|
players[i] zm_utility::zm_dash_stats_game_end();
|
|
}
|
|
|
|
//LUINotifyEvent( &"force_scoreboard", 0 );
|
|
|
|
UploadStats();
|
|
zm_stats::update_players_stats_at_match_end( players );
|
|
zm_stats::update_global_counters_on_match_end();
|
|
bb::logroundevent("end_game");
|
|
upload_leaderboards();
|
|
|
|
recordGameResult( "draw" );
|
|
globallogic::recordZMEndGameComScoreEvent( "draw" );
|
|
globallogic_player::recordActivePlayersEndGameMatchRecordStats();
|
|
updateEndOfMatchCounters();
|
|
|
|
//update dash and promo counters
|
|
if( SessionModeIsOnlineGame() )
|
|
{
|
|
level thread zm_utility::upload_zm_dash_counters_end_game();
|
|
}
|
|
|
|
// Finalize Match Record
|
|
finalizeMatchRecord();
|
|
|
|
//zm_utility::play_sound_at_pos( "end_of_game", ( 0, 0, 0 ) );
|
|
|
|
players = GetPlayers();
|
|
foreach( player in players )
|
|
{
|
|
if( IsDefined( player.sessionstate ) && player.sessionstate == "spectator" )
|
|
{
|
|
player.sessionstate = "playing";
|
|
player thread end_game_player_was_spectator();
|
|
}
|
|
}
|
|
{wait(.05);};
|
|
|
|
/#
|
|
if ( !( isdefined( level.host_ended_game ) && level.host_ended_game ) && GetDvarInt( "scr_restart_on_wipe" ) > 1 )
|
|
{
|
|
LUINotifyEvent( &"force_scoreboard", 0 );
|
|
map_restart( true );
|
|
wait( 666 );
|
|
}
|
|
#/
|
|
|
|
players = GetPlayers();
|
|
|
|
LUINotifyEvent( &"force_scoreboard", 1, 1 );
|
|
|
|
intermission();
|
|
|
|
wait( level.zombie_vars["zombie_intermission_time"] );
|
|
|
|
// hide the gameover message
|
|
if ( !isDefined( level._supress_survived_screen ) )
|
|
{
|
|
for ( i = 0; i < players.size; i++ )
|
|
{
|
|
survived[i] Destroy();
|
|
game_over[i] Destroy();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( i = 0; i < players.size; i++ )
|
|
{
|
|
if(isDefined(players[i].survived_hud ) )
|
|
players[i].survived_hud Destroy();
|
|
if (isDefined( players[i].game_over_hud ) )
|
|
players[i].game_over_hud Destroy();
|
|
}
|
|
}
|
|
|
|
level notify( "stop_intermission" );
|
|
array::thread_all( GetPlayers(), &player_exit_level );
|
|
|
|
wait( 1.5 );
|
|
|
|
players = GetPlayers();
|
|
for ( i = 0; i < players.size; i++ )
|
|
{
|
|
players[i] CameraActivate( false );
|
|
}
|
|
|
|
/#
|
|
if ( !( isdefined( level.host_ended_game ) && level.host_ended_game ) && GetDvarInt( "scr_restart_on_wipe" ) )
|
|
{
|
|
LUINotifyEvent( &"force_scoreboard", 1, 0 );
|
|
map_restart( true );
|
|
wait( 666 );
|
|
}
|
|
#/
|
|
|
|
ExitLevel( false );
|
|
|
|
// Let's not exit the function
|
|
wait( 666 );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function end_game_player_was_spectator()
|
|
{
|
|
{wait(.05);};
|
|
|
|
self Ghost();
|
|
self FreezeControls( true );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function disable_end_game_intermission( delay )
|
|
{
|
|
level.disable_intermission = true;
|
|
wait( delay );
|
|
level.disable_intermission = undefined;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function check_end_game_intermission_delay()
|
|
{
|
|
if( IsDefined(level.disable_intermission) )
|
|
{
|
|
while( 1 )
|
|
{
|
|
if( !IsDefined(level.disable_intermission) )
|
|
{
|
|
break;
|
|
}
|
|
wait( 0.01 );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
// This will save the leaderboard data per round, for use in single player
|
|
//*****************************************************************************
|
|
|
|
function upload_leaderboards()
|
|
{
|
|
// place restrictions on whether leaderboards are uploaded to in the precache leaderboards function
|
|
players = GetPlayers();
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
players[i] uploadleaderboards();
|
|
}
|
|
}
|
|
|
|
|
|
function initializeStatTracking()
|
|
{
|
|
level.global_zombies_killed = 0;
|
|
level.zombies_timeout_spawn = 0;
|
|
level.zombies_timeout_playspace = 0;
|
|
level.zombies_timeout_undamaged = 0;
|
|
level.zombie_player_killed_count = 0;
|
|
level.zombie_trap_killed_count = 0;
|
|
level.zombie_pathing_failed = 0;
|
|
level.zombie_breadcrumb_failed = 0;
|
|
|
|
}
|
|
|
|
function uploadGlobalStatCounters()
|
|
{
|
|
incrementCounter( "global_zombies_killed", level.global_zombies_killed );
|
|
incrementCounter( "global_zombies_killed_by_players", level.zombie_player_killed_count );
|
|
incrementCounter( "global_zombies_killed_by_traps", level.zombie_trap_killed_count );
|
|
}
|
|
|
|
function player_fake_death()
|
|
{
|
|
level notify ("fake_death");
|
|
self notify ("fake_death");
|
|
|
|
self TakeAllWeapons();
|
|
self AllowStand( false );
|
|
self AllowCrouch( false );
|
|
self AllowProne( true );
|
|
|
|
self.ignoreme = true;
|
|
self EnableInvulnerability();
|
|
|
|
wait( 1 );
|
|
self FreezeControls( true );
|
|
}
|
|
|
|
function player_exit_level()
|
|
{
|
|
self AllowStand( true );
|
|
self AllowCrouch( false );
|
|
self AllowProne( false );
|
|
|
|
//self thread lui::screen_fade_out( 1 );
|
|
}
|
|
|
|
|
|
function player_killed_override(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration)
|
|
{
|
|
// BLANK
|
|
level waittill( "forever" );
|
|
}
|
|
|
|
function player_zombie_breadcrumb()
|
|
{
|
|
self notify("stop_player_zombie_breadcrumb");
|
|
self endon("stop_player_zombie_breadcrumb");
|
|
self endon( "disconnect" );
|
|
self endon( "spawned_spectator" );
|
|
level endon( "intermission" );
|
|
|
|
self.zombie_breadcrumbs = [];
|
|
self.zombie_breadcrumb_distance = 24 * 24; // min dist (squared) the player must move to drop a crumb
|
|
self.zombie_breadcrumb_area_num = 3; // the number of "rings" the area breadcrumbs use
|
|
self.zombie_breadcrumb_area_distance = 16; // the distance between each "ring" of the area breadcrumbs
|
|
|
|
self store_crumb( self.origin );
|
|
last_crumb = self.origin;
|
|
|
|
self thread zm_utility::debug_breadcrumbs();
|
|
|
|
while( 1 )
|
|
{
|
|
wait_time = 0.1;
|
|
|
|
|
|
if( self.ignoreme )
|
|
{
|
|
wait( wait_time );
|
|
continue;
|
|
}
|
|
|
|
//For cloaking ability
|
|
//if( self.ignoreme )
|
|
//{
|
|
// wait( wait_time );
|
|
// continue;
|
|
//}
|
|
|
|
|
|
store_crumb = true;
|
|
airborne = false;
|
|
crumb = self.origin;
|
|
|
|
//TODO TEMP SCRIPT for vehicle testing Delete/comment when done
|
|
if ( !self IsOnGround() && self isinvehicle() )
|
|
{
|
|
trace = bullettrace( self.origin + (0,0,10), self.origin, false, undefined );
|
|
crumb = trace["position"];
|
|
}
|
|
|
|
//TODO TEMP DISABLE for vehicle testing. Uncomment when reverting
|
|
// if ( !self IsOnGround() )
|
|
// {
|
|
// airborne = true;
|
|
// store_crumb = false;
|
|
// wait_time = 0.05;
|
|
// }
|
|
//
|
|
if( !airborne && DistanceSquared( crumb, last_crumb ) < self.zombie_breadcrumb_distance )
|
|
{
|
|
store_crumb = false;
|
|
}
|
|
|
|
if ( airborne && self IsOnGround() )
|
|
{
|
|
// player was airborne, store crumb now that he's on the ground
|
|
store_crumb = true;
|
|
airborne = false;
|
|
}
|
|
|
|
if( isDefined( level.custom_breadcrumb_store_func ) )
|
|
{
|
|
store_crumb = self [[ level.custom_breadcrumb_store_func ]]( store_crumb );
|
|
}
|
|
|
|
if( isDefined( level.custom_airborne_func ) )
|
|
{
|
|
airborne = self [[ level.custom_airborne_func ]]( airborne );
|
|
}
|
|
|
|
if( store_crumb )
|
|
{
|
|
zm_utility::debug_print( "Player is storing breadcrumb " + crumb );
|
|
|
|
if( IsDefined(self.node) )
|
|
{
|
|
zm_utility::debug_print( "has closest node " );
|
|
}
|
|
|
|
last_crumb = crumb;
|
|
self store_crumb( crumb );
|
|
}
|
|
|
|
wait( wait_time );
|
|
}
|
|
}
|
|
|
|
|
|
function store_crumb( origin )
|
|
{
|
|
offsets = [];
|
|
height_offset = 32;
|
|
|
|
index = 0;
|
|
for( j = 1; j <= self.zombie_breadcrumb_area_num; j++ )
|
|
{
|
|
offset = ( j * self.zombie_breadcrumb_area_distance );
|
|
|
|
offsets[0] = ( origin[0] - offset, origin[1], origin[2] );
|
|
offsets[1] = ( origin[0] + offset, origin[1], origin[2] );
|
|
offsets[2] = ( origin[0], origin[1] - offset, origin[2] );
|
|
offsets[3] = ( origin[0], origin[1] + offset, origin[2] );
|
|
|
|
offsets[4] = ( origin[0] - offset, origin[1], origin[2] + height_offset );
|
|
offsets[5] = ( origin[0] + offset, origin[1], origin[2] + height_offset );
|
|
offsets[6] = ( origin[0], origin[1] - offset, origin[2] + height_offset );
|
|
offsets[7] = ( origin[0], origin[1] + offset, origin[2] + height_offset );
|
|
|
|
for ( i = 0; i < offsets.size; i++ )
|
|
{
|
|
self.zombie_breadcrumbs[index] = offsets[i];
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////LEADERBOARD CODE///////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
function to_mins( seconds )
|
|
{
|
|
hours = 0;
|
|
minutes = 0;
|
|
|
|
if( seconds > 59 )
|
|
{
|
|
minutes = int( seconds / 60 );
|
|
|
|
seconds = int( seconds * 1000 ) % ( 60 * 1000 );
|
|
seconds = seconds * 0.001;
|
|
|
|
if( minutes > 59 )
|
|
{
|
|
hours = int( minutes / 60 );
|
|
minutes = int( minutes * 1000 ) % ( 60 * 1000 );
|
|
minutes = minutes * 0.001;
|
|
}
|
|
}
|
|
|
|
if( hours < 10 )
|
|
{
|
|
hours = "0" + hours;
|
|
}
|
|
|
|
if( minutes < 10 )
|
|
{
|
|
minutes = "0" + minutes;
|
|
}
|
|
|
|
seconds = Int( seconds );
|
|
if( seconds < 10 )
|
|
{
|
|
seconds = "0" + seconds;
|
|
}
|
|
|
|
combined = "" + hours + ":" + minutes + ":" + seconds;
|
|
|
|
return combined;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// INTERMISSION =========================================================== //
|
|
//
|
|
|
|
function intermission()
|
|
{
|
|
level.intermission = true;
|
|
level notify( "intermission" );
|
|
|
|
players = GetPlayers();
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
players[i] SetClientThirdPerson( 0 );
|
|
players[i] resetFov();
|
|
|
|
players[i].health = 100; // This is needed so the player view doesn't get stuck
|
|
players[i] thread [[level.custom_intermission]]();
|
|
|
|
players[i] StopSounds();
|
|
}
|
|
|
|
wait( 5.25 );
|
|
|
|
players = GetPlayers();
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
players[i] clientfield::set( "zmbLastStand", 0 );
|
|
}
|
|
|
|
level thread zombie_game_over_death();
|
|
}
|
|
|
|
function zombie_game_over_death()
|
|
{
|
|
// Kill remaining zombies, in style!
|
|
zombies = GetAiTeamArray( level.zombie_team );
|
|
for( i = 0; i < zombies.size; i++ )
|
|
{
|
|
if( !IsAlive( zombies[i] ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
zombies[i] SetGoal( zombies[i].origin );
|
|
}
|
|
|
|
for( i = 0; i < zombies.size; i++ )
|
|
{
|
|
if( !IsAlive( zombies[i] ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( ( isdefined( zombies[i].ignore_game_over_death ) && zombies[i].ignore_game_over_death ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
wait( 0.5 + RandomFloat( 2 ) );
|
|
|
|
if ( isdefined( zombies[i] ) )
|
|
{
|
|
if( !IsVehicle( zombies[i] ) )
|
|
{
|
|
zombies[i] zombie_utility::zombie_head_gib();
|
|
}
|
|
|
|
zombies[i] Kill();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
function screen_fade_in( n_time, v_color, str_menu_id )
|
|
{
|
|
lui::screen_fade( n_time, 0, 1, v_color, false, str_menu_id );
|
|
wait n_time;
|
|
}
|
|
|
|
|
|
function player_intermission()
|
|
{
|
|
self closeInGameMenu();
|
|
self CloseMenu( "StartMenu_Main" );
|
|
|
|
self notify("player_intermission");
|
|
self endon("player_intermission");
|
|
level endon( "stop_intermission" );
|
|
self endon("disconnect");
|
|
self endon("death");
|
|
self notify( "_zombie_game_over" ); // ww: notify so hud elements know when to leave
|
|
|
|
//Show total gained point for end scoreboard and lobby
|
|
self.score = self.score_total;
|
|
|
|
points =struct::get_array( "intermission", "targetname" );
|
|
|
|
if( !IsDefined( points ) || points.size == 0 )
|
|
{
|
|
points = getentarray( "info_intermission", "classname" );
|
|
if( points.size < 1 )
|
|
{
|
|
/# println( "NO info_intermission POINTS IN MAP" ); #/
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( ( isdefined( level.b_show_single_intermission ) && level.b_show_single_intermission ) )
|
|
{
|
|
a_s_temp_points = array::randomize( points );
|
|
points = [];
|
|
points[0] = array::random( a_s_temp_points );
|
|
}
|
|
else
|
|
{
|
|
points = array::randomize( points );
|
|
}
|
|
|
|
self zm_utility::create_streamer_hint( points[0].origin, points[0].angles, 0.9 );
|
|
|
|
wait( 5 );
|
|
|
|
self lui::screen_fade_out( 1 );
|
|
|
|
// don't do this unti we're ready to "spawn" the players in the exit scenes
|
|
// the player camera will clip into the ground if this is done too early
|
|
self.sessionstate = "intermission";
|
|
self.spectatorclient = -1;
|
|
self.killcamentity = -1;
|
|
self.archivetime = 0;
|
|
self.psoffsettime = 0;
|
|
self.friendlydamage = undefined;
|
|
if ( isdefined( level.player_intemission_spawn_callback ) )
|
|
{
|
|
self thread [[ level.player_intemission_spawn_callback ]] ( points[0].origin, points[0].angles );
|
|
}
|
|
|
|
while( 1 )
|
|
{
|
|
for( i = 0; i < points.size; i++ )
|
|
{
|
|
point = points[i];
|
|
nextpoint = points[i+1];
|
|
|
|
self SetOrigin( point.origin );
|
|
self SetPlayerAngles( point.angles );
|
|
wait 0.15;
|
|
|
|
self notify("player_intermission_spawned");
|
|
|
|
if ( IsDefined(nextpoint) )
|
|
{
|
|
self zm_utility::create_streamer_hint( nextpoint.origin, nextpoint.angles, 0.9 );
|
|
self screen_fade_in( 2 );
|
|
|
|
wait( 3 );
|
|
|
|
self lui::screen_fade_out( 2 );
|
|
}
|
|
else
|
|
{
|
|
self screen_fade_in( 2 );
|
|
|
|
if ( points.size == 1 )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function fade_up_over_time(t)
|
|
{
|
|
self FadeOverTime( t );
|
|
self.alpha = 1;
|
|
}
|
|
|
|
function default_exit_level()
|
|
{
|
|
zombies = GetAiTeamArray( level.zombie_team );
|
|
for ( i = 0; i < zombies.size; i++ )
|
|
{
|
|
if ( ( isdefined( zombies[i].ignore_solo_last_stand ) && zombies[i].ignore_solo_last_stand ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( isDefined( zombies[i].find_exit_point ) )
|
|
{
|
|
zombies[i] thread [[ zombies[i].find_exit_point ]]();
|
|
continue;
|
|
}
|
|
|
|
if ( zombies[i].ignoreme )
|
|
{
|
|
zombies[i] thread default_delayed_exit();
|
|
}
|
|
else
|
|
{
|
|
zombies[i] thread default_find_exit_point();
|
|
}
|
|
}
|
|
}
|
|
|
|
function default_delayed_exit()
|
|
{
|
|
self endon( "death" );
|
|
|
|
while ( 1 )
|
|
{
|
|
if ( !level flag::get( "wait_and_revive" ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// broke through the barricade, find an exit point
|
|
if ( !self.ignoreme )
|
|
{
|
|
break;
|
|
}
|
|
wait( 0.1 );
|
|
}
|
|
|
|
self thread default_find_exit_point();
|
|
}
|
|
|
|
function default_find_exit_point()
|
|
{
|
|
self endon( "death" );
|
|
|
|
player = GetPlayers()[0];
|
|
|
|
dist_zombie = 0;
|
|
dist_player = 0;
|
|
dest = 0;
|
|
|
|
away = VectorNormalize( self.origin - player.origin );
|
|
endPos = self.origin + VectorScale( away, 600 );
|
|
|
|
if ( isdefined( level.zm_loc_types[ "wait_location" ] ) && level.zm_loc_types[ "wait_location" ].size > 0 )
|
|
{
|
|
locs = array::randomize( level.zm_loc_types[ "wait_location" ] );
|
|
}
|
|
//TODO Add wait_locations to Der Reise and we can remove this line
|
|
else // Legacy catch
|
|
{
|
|
locs = array::randomize( level.zm_loc_types[ "dog_location" ] );
|
|
}
|
|
|
|
for ( i = 0; i < locs.size; i++ )
|
|
{
|
|
dist_zombie = DistanceSquared( locs[i].origin, endPos );
|
|
dist_player = DistanceSquared( locs[i].origin, player.origin );
|
|
|
|
if ( dist_zombie < dist_player )
|
|
{
|
|
dest = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
self notify( "stop_find_flesh" );
|
|
self notify( "zombie_acquire_enemy" );
|
|
|
|
if( isdefined( locs[dest] ) )
|
|
{
|
|
self SetGoal( locs[dest].origin );
|
|
}
|
|
|
|
while ( 1 )
|
|
{
|
|
// in the event this function isn't run through a solo revive, use level override to dictate behavior; don't change existing behavior if this doesn't exist
|
|
b_passed_override = true;
|
|
|
|
// Returning 'false' from the level override will put zombies back into find_flesh
|
|
if ( IsDefined( level.default_find_exit_position_override ) )
|
|
{
|
|
b_passed_override = [[ level.default_find_exit_position_override ]]();
|
|
}
|
|
|
|
if ( !level flag::get( "wait_and_revive" ) && b_passed_override )
|
|
{
|
|
break;
|
|
}
|
|
wait( 0.1 );
|
|
}
|
|
|
|
}
|
|
|
|
function play_level_start_vox_delayed()
|
|
{
|
|
wait(3);
|
|
players = GetPlayers();
|
|
num = RandomIntRange( 0, players.size );
|
|
players[num] zm_audio::create_and_play_dialog( "general", "intro" );
|
|
}
|
|
|
|
|
|
function register_sidequest( id, sidequest_stat )
|
|
{
|
|
if ( !IsDefined( level.zombie_sidequest_stat ) )
|
|
{
|
|
level.zombie_sidequest_previously_completed = [];
|
|
level.zombie_sidequest_stat = [];
|
|
}
|
|
|
|
level.zombie_sidequest_stat[id] = sidequest_stat;
|
|
|
|
//level flag::wait_till( "all_players_spawned" );
|
|
level flag::wait_till( "start_zombie_round_logic" );
|
|
|
|
level.zombie_sidequest_previously_completed[id] = false;
|
|
|
|
// don't do stats stuff if it's not an online game
|
|
if ( !level.onlineGame )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//don't do stats stuff if stats are disabled
|
|
if ( ( isdefined( level.zm_disable_recording_stats ) && level.zm_disable_recording_stats ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
players = GetPlayers();
|
|
for ( i = 0; i < players.size; i++ )
|
|
{
|
|
if ( players[i] zm_stats::get_global_stat( level.zombie_sidequest_stat[id] ) )
|
|
{
|
|
level.zombie_sidequest_previously_completed[id] = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function is_sidequest_previously_completed(id)
|
|
{
|
|
return ( isdefined( level.zombie_sidequest_previously_completed[id] ) && level.zombie_sidequest_previously_completed[id] );
|
|
}
|
|
|
|
|
|
function set_sidequest_completed(id)
|
|
{
|
|
level notify( "zombie_sidequest_completed", id );
|
|
level.zombie_sidequest_previously_completed[id] = true;
|
|
|
|
// don't do stats stuff if it's not an online game
|
|
if ( !level.onlineGame )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//don't do stats stuff if stats are disabled
|
|
if ( ( isdefined( level.zm_disable_recording_stats ) && level.zm_disable_recording_stats ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
players = GetPlayers();
|
|
for ( i = 0; i < players.size; i++ )
|
|
{
|
|
if ( isdefined( level.zombie_sidequest_stat[id] ) )
|
|
{
|
|
players[i] zm_stats::add_global_stat( level.zombie_sidequest_stat[id], 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
function playSwipeSound( mod, attacker )
|
|
{
|
|
if( ( isdefined( attacker.is_zombie ) && attacker.is_zombie ) || (isdefined( attacker.archetype ) && attacker.archetype == "margwa" ) )
|
|
{
|
|
self playsoundtoplayer( "evt_player_swiped", self );
|
|
return;
|
|
}
|
|
}
|
|
|
|
function precache_zombie_leaderboards()
|
|
{
|
|
// don't save leaderboards for systemlink or custom games
|
|
if( SessionModeIsSystemlink() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// GLOBAL LEADERBOARDS
|
|
globalLeaderboards = "LB_ZM_GB_BULLETS_FIRED_AT ";
|
|
globalLeaderboards += "LB_ZM_GB_BULLETS_HIT_AT ";
|
|
globalLeaderboards += "LB_ZM_GB_DISTANCE_TRAVELED_AT ";
|
|
globalLeaderboards += "LB_ZM_GB_DOORS_PURCHASED_AT ";
|
|
globalLeaderboards += "LB_ZM_GB_GRENADE_KILLS_AT ";
|
|
globalLeaderboards += "LB_ZM_GB_HEADSHOTS_AT ";
|
|
globalLeaderboards += "LB_ZM_GB_KILLS_AT ";
|
|
globalLeaderboards += "LB_ZM_GB_PERKS_DRANK_AT ";
|
|
globalLeaderboards += "LB_ZM_GB_REVIVES_AT ";
|
|
|
|
//Multirank
|
|
globalLeaderboards += "LB_ZM_GB_KILLSTATS_MR ";
|
|
globalLeaderboards += "LB_ZM_GB_GAMESTATS_MR ";
|
|
|
|
if ( !level.rankedMatch && (GetDvarInt( "zm_private_rankedmatch", 0 ) == 0) )
|
|
{
|
|
precacheLeaderboards( globalLeaderboards );
|
|
return;
|
|
}
|
|
|
|
// MAP LEADERBOARD
|
|
mapname = GetDvarString( "mapname" );
|
|
expectedPlayerNum = GetNumExpectedPlayers();
|
|
|
|
mapLeaderboard = "LB_ZM_MAP_"+ getsubstr( mapname, 3, mapname.size ) + "_" + expectedPlayerNum + "PLAYER";
|
|
|
|
precacheLeaderboards( globalLeaderboards + mapLeaderboard );
|
|
}
|
|
|
|
function zm_on_player_connect()
|
|
{
|
|
if( level.passed_introscreen)
|
|
{
|
|
self setClientUIVisibilityFlag( "hud_visible", 1 );
|
|
self setClientUIVisibilityFlag( "weapon_hud_visible", 1 );
|
|
|
|
zm_utility::increment_zm_dash_counter( "hotjoined", 1 );
|
|
zm_utility::upload_zm_dash_counters();
|
|
}
|
|
|
|
self flag::init( "used_consumable" );
|
|
self thread zm_utility::zm_dash_stats_game_start();
|
|
self thread zm_utility::zm_dash_stats_wait_for_consumable_use();
|
|
|
|
thread refresh_player_navcard_hud();
|
|
self thread watchDisconnect();
|
|
|
|
self.hud_damagefeedback = newdamageindicatorhudelem(self);
|
|
self.hud_damagefeedback.horzAlign = "center";
|
|
self.hud_damagefeedback.vertAlign = "middle";
|
|
self.hud_damagefeedback.x = -12;
|
|
self.hud_damagefeedback.y = -12;
|
|
self.hud_damagefeedback.alpha = 0;
|
|
self.hud_damagefeedback.archived = true;
|
|
self.hud_damagefeedback setShader( "damage_feedback", 24, 48 );
|
|
self.hitSoundTracker = true;
|
|
|
|
}
|
|
|
|
function zm_on_player_disconnect()
|
|
{
|
|
thread refresh_player_navcard_hud();
|
|
|
|
zm_utility::increment_zm_dash_counter( "left_midgame", 1 );
|
|
zm_utility::upload_zm_dash_counters();
|
|
}
|
|
|
|
function watchDisconnect()
|
|
{
|
|
self notify("watchDisconnect");
|
|
self endon("watchDisconnect");
|
|
self waittill("disconnect");
|
|
zm_on_player_disconnect();
|
|
}
|
|
|
|
|
|
|
|
function increment_dog_round_stat(stat)
|
|
{
|
|
players = GetPlayers();
|
|
foreach(player in players)
|
|
{
|
|
player zm_stats::increment_client_stat( "zdog_rounds_" + stat );
|
|
}
|
|
}
|
|
|
|
function setup_player_navcard_hud()
|
|
{
|
|
level flag::wait_till( "start_zombie_round_logic" );
|
|
thread refresh_player_navcard_hud();
|
|
}
|
|
|
|
|
|
function refresh_player_navcard_hud()
|
|
{
|
|
if (!IsDefined(level.navcards))
|
|
return;
|
|
players = GetPlayers();
|
|
foreach( player in players )
|
|
{
|
|
navcard_bits = 0;
|
|
for(i = 0;i < level.navcards.size; i++)
|
|
{
|
|
hasit = player zm_stats::get_global_stat( level.navcards[i] );
|
|
if (isdefined(player.navcard_grabbed) && player.navcard_grabbed == level.navcards[i] )
|
|
hasit = 1;
|
|
if( hasit )
|
|
{
|
|
navcard_bits +=( 1 << i );
|
|
}
|
|
}
|
|
util::wait_network_frame();
|
|
player clientfield::set( "navcard_held", 0 );
|
|
if ( navcard_bits > 0 )
|
|
{
|
|
util::wait_network_frame();
|
|
player clientfield::set( "navcard_held", navcard_bits );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function set_default_laststand_pistol(solo_mode)
|
|
{
|
|
|
|
if (!solo_mode )
|
|
{
|
|
level.laststandpistol = level.default_laststandpistol;
|
|
}
|
|
else
|
|
{
|
|
level.laststandpistol = level.default_solo_laststandpistol;
|
|
}
|
|
|
|
}
|
|
|
|
//109171 Zombies - ZM_Global - Add check for player count at beginning of the game
|
|
//monitors during the match for exploits extra players being able to join the match
|
|
function player_too_many_players_check()
|
|
{
|
|
max_players = 4;
|
|
if ( level.scr_zm_ui_gametype == "zgrief" || level.scr_zm_ui_gametype == "zmeat" )
|
|
{
|
|
max_players = 8;
|
|
}
|
|
|
|
if ( GetPlayers().size > max_players )
|
|
{
|
|
zm_game_module::freeze_players(true);
|
|
level notify("end_game");
|
|
}
|
|
|
|
}
|
|
|
|
//vehicle response to idgun damage
|
|
function is_idgun_damage( weapon )
|
|
{
|
|
if( isdefined( level.idgun_weapons ) )
|
|
{
|
|
if ( IsInArray( level.idgun_weapons, weapon ) )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function zm_on_player_spawned()
|
|
{
|
|
thread update_zone_name();
|
|
thread update_is_player_valid();
|
|
}
|
|
|
|
function update_is_player_valid()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnnect" );
|
|
|
|
self.am_i_valid = true;
|
|
while ( isDefined( self ) )
|
|
{
|
|
self.am_i_valid = zm_utility::is_player_valid( self, true );
|
|
{wait(.05);}
|
|
}
|
|
}
|
|
|
|
function update_zone_name()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnnect" );
|
|
|
|
self.zone_name = zm_utility::get_current_zone();
|
|
if ( isDefined( self.zone_name ) )
|
|
{
|
|
self.previous_zone_name = self.zone_name;
|
|
}
|
|
|
|
while ( isDefined( self ) )
|
|
{
|
|
if( isDefined( self.zone_name ) )
|
|
{
|
|
self.previous_zone_name = self.zone_name;
|
|
}
|
|
self.zone_name = zm_utility::get_current_zone();
|
|
|
|
wait RandomFloatRange( 0.5, 1.0 );
|
|
}
|
|
}
|
|
|
|
/#
|
|
function printHashIDs()
|
|
{
|
|
outputString = "\n------------------- BEGIN HASH ID DUMP -----------------------------\n";
|
|
|
|
|
|
//Print Craftables
|
|
outputString += "** CRAFTABLES **\n";
|
|
foreach( s_craftable in level.zombie_include_craftables )
|
|
{
|
|
outputString += "+" + s_craftable.name + "," + s_craftable.hash_id + "\n";
|
|
if (!isDefined(s_craftable.a_piecestubs))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach( s_piece in s_craftable.a_piecestubs )
|
|
{
|
|
outputString += s_piece.pieceName + "," + s_piece.hash_id + "\n";
|
|
}
|
|
}
|
|
|
|
//Print Powerups
|
|
outputString += "** POWERUPS **\n";
|
|
foreach ( powerup in level.zombie_powerups)
|
|
{
|
|
outputString += powerup.powerup_name + "," + powerup.hash_id + "\n";
|
|
}
|
|
|
|
//Print AATs
|
|
outputString += "** AAT **\n";
|
|
if( ( isdefined( level.aat_in_use ) && level.aat_in_use ) )
|
|
{
|
|
foreach (aat in level.aat)
|
|
{
|
|
if (!isDefined(aat) || !isDefined(aat.name) || aat.name == "none")
|
|
{
|
|
continue;
|
|
}
|
|
outputString += aat.name + "," + aat.hash_id + "\n";
|
|
}
|
|
}
|
|
|
|
//Print AATs
|
|
outputString += "** PERKS **\n";
|
|
foreach (perk in level._custom_perks)
|
|
{
|
|
if (!isDefined(perk) || !isDefined(perk.alias))
|
|
{
|
|
continue;
|
|
}
|
|
outputString += perk.alias + "," + perk.hash_id + "\n";
|
|
}
|
|
|
|
outputString += "------------------- END HASH ID DUMP -----------------------------\n";
|
|
PrintLn(outputString);
|
|
}
|
|
|
|
#/
|