From 88cbdf413ca9a20ef2f0d75bf33dcf6083264f59 Mon Sep 17 00:00:00 2001 From: JezuzLizard Date: Sun, 31 May 2020 18:16:33 -0700 Subject: [PATCH] uploaded 15 scripts as a baseline for zm_prison_patch --- .../maps/mp/zombies/_zm_afterlife.gsc | 2289 ++++++++++++ .../maps/mp/zombies/_zm_ai_brutus.gsc | 2939 +++++++++++++++ .../maps/mp/zombies/_zm_craftables.gsc | 3192 +++++++++++++++++ .../maps/mp/zombies/_zm_game_module_grief.gsc | 11 + .../maps/mp/zombies/_zm_game_module_meat.gsc | 6 + .../zombies/_zm_game_module_meat_utility.gsc | 685 ++++ .../mp/zombies/_zm_game_module_utility.gsc | 46 + .../maps/mp/zombies/_zm_magicbox_prison.gsc | 217 ++ .../maps/mp/zombies/_zm_melee_weapon.gsc | 556 +++ .../mp/zombies/_zm_perk_electric_cherry.gsc | 391 ++ .../maps/mp/zombies/_zm_riotshield_prison.gsc | 670 ++++ .../mp/zombies/_zm_weap_ballistic_knife.gsc | 278 ++ .../maps/mp/zombies/_zm_weap_claymore.gsc | 492 +++ .../mp/zombies/_zm_weap_riotshield_prison.gsc | 778 ++++ .../maps/mp/zombies/_zm_weap_tomahawk.gsc | 672 ++++ zm_prison_patch/readme.md | 15 +- 16 files changed, 13236 insertions(+), 1 deletion(-) create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_afterlife.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_ai_brutus.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_craftables.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_game_module_grief.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_game_module_meat.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_game_module_meat_utility.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_game_module_utility.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_magicbox_prison.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_melee_weapon.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_perk_electric_cherry.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_riotshield_prison.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_weap_ballistic_knife.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_weap_claymore.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_weap_riotshield_prison.gsc create mode 100644 zm_prison_patch/maps/mp/zombies/_zm_weap_tomahawk.gsc diff --git a/zm_prison_patch/maps/mp/zombies/_zm_afterlife.gsc b/zm_prison_patch/maps/mp/zombies/_zm_afterlife.gsc new file mode 100644 index 0000000..dc2a5a9 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_afterlife.gsc @@ -0,0 +1,2289 @@ +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/animscripts/shared; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zm_alcatraz_travel; +#include maps/mp/gametypes_zm/_zm_gametype; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_clone; +#include maps/mp/zombies/_zm_perk_electric_cherry; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm; +#include maps/mp/_visionset_mgr; +#include maps/mp/zm_alcatraz_utility; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +#using_animtree( "fxanim_props" ); + +init() +{ + level.zombiemode_using_afterlife = 1; + flag_init( "afterlife_start_over" ); + level.afterlife_revive_tool = "syrette_afterlife_zm"; + precacheitem( level.afterlife_revive_tool ); + precachemodel( "drone_collision" ); + maps/mp/_visionset_mgr::vsmgr_register_info( "visionset", "zm_afterlife", 9000, 120, 1, 1 ); + maps/mp/_visionset_mgr::vsmgr_register_info( "overlay", "zm_afterlife_filter", 9000, 120, 1, 1 ); + if ( isDefined( level.afterlife_player_damage_override ) ) + { + maps/mp/zombies/_zm::register_player_damage_callback( level.afterlife_player_damage_override ); + } + else + { + maps/mp/zombies/_zm::register_player_damage_callback( ::afterlife_player_damage_callback ); + } + registerclientfield( "toplayer", "player_lives", 9000, 2, "int" ); + registerclientfield( "toplayer", "player_in_afterlife", 9000, 1, "int" ); + registerclientfield( "toplayer", "player_afterlife_mana", 9000, 5, "float" ); + registerclientfield( "allplayers", "player_afterlife_fx", 9000, 1, "int" ); + registerclientfield( "toplayer", "clientfield_afterlife_audio", 9000, 1, "int" ); + registerclientfield( "toplayer", "player_afterlife_refill", 9000, 1, "int" ); + registerclientfield( "scriptmover", "player_corpse_id", 9000, 3, "int" ); + afterlife_load_fx(); + level thread afterlife_hostmigration(); + precachemodel( "c_zom_ghost_viewhands" ); + precachemodel( "c_zom_hero_ghost_fb" ); + precacheitem( "lightning_hands_zm" ); + precachemodel( "p6_zm_al_shock_box_on" ); + precacheshader( "waypoint_revive_afterlife" ); + a_afterlife_interact = getentarray( "afterlife_interact", "targetname" ); + array_thread( a_afterlife_interact, ::afterlife_interact_object_think ); + level.zombie_spawners = getentarray( "zombie_spawner", "script_noteworthy" ); + array_thread( level.zombie_spawners, ::add_spawn_function, ::afterlife_zombie_damage ); + a_afterlife_triggers = getstructarray( "afterlife_trigger", "targetname" ); + _a87 = a_afterlife_triggers; + _k87 = getFirstArrayKey( _a87 ); + while ( isDefined( _k87 ) ) + { + struct = _a87[ _k87 ]; + afterlife_trigger_create( struct ); + _k87 = getNextArrayKey( _a87, _k87 ); + } + level.afterlife_interact_dist = 256; + level.is_player_valid_override = ::is_player_valid_afterlife; + level.can_revive = ::can_revive_override; + level.round_prestart_func = ::afterlife_start_zombie_logic; + level.custom_pap_validation = ::is_player_valid_afterlife; + level.player_out_of_playable_area_monitor_callback = ::player_out_of_playable_area; + level thread afterlife_gameover_cleanup(); + level.afterlife_get_spawnpoint = ::afterlife_get_spawnpoint; + level.afterlife_zapped = ::afterlife_zapped; + level.afterlife_give_loadout = ::afterlife_give_loadout; + level.afterlife_save_loadout = ::afterlife_save_loadout; +} + +afterlife_gameover_cleanup() +{ + level waittill( "end_game" ); + _a126 = getplayers(); + _k126 = getFirstArrayKey( _a126 ); + while ( isDefined( _k126 ) ) + { + player = _a126[ _k126 ]; + player.afterlife = 0; + player clientnotify( "end_game" ); + player notify( "end_game" ); + if ( isDefined( player.client_hint ) ) + { + player.client_hint destroy(); + } + _k126 = getNextArrayKey( _a126, _k126 ); + } + wait 5; + _a141 = getplayers(); + _k141 = getFirstArrayKey( _a141 ); + while ( isDefined( _k141 ) ) + { + player = _a141[ _k141 ]; + if ( isDefined( level.optimise_for_splitscreen ) && !level.optimise_for_splitscreen ) + { + maps/mp/_visionset_mgr::vsmgr_deactivate( "overlay", "zm_afterlife_filter", player ); + } + _k141 = getNextArrayKey( _a141, _k141 ); + } +} + +afterlife_load_fx() +{ + level._effect[ "afterlife_teleport" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_afterlife_zmb_tport" ); + level._effect[ "teleport_ball" ] = loadfx( "weapon/tomahawk/fx_tomahawk_trail_ug" ); + level._effect[ "afterlife_kill_point_fx" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_suicide_area" ); + level._effect[ "afterlife_enter" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_afterlife_start" ); + level._effect[ "afterlife_leave" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_player_revive" ); + level._effect[ "afterlife_pixie_dust" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_afterlife_pixies" ); + level._effect[ "afterlife_corpse" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_player_down" ); + level._effect[ "afterlife_damage" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_afterlife_damage" ); + level._effect[ "afterlife_ghost_fx" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_ghost_body" ); + level._effect[ "afterlife_ghost_h_fx" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_ghost_head" ); + level._effect[ "afterlife_ghost_arm_fx" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_ghost_arm" ); + level._effect[ "afterlife_ghost_hand_fx" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_ghost_hand" ); + level._effect[ "afterlife_ghost_hand_r_fx" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_ghost_hand_r" ); + level._effect[ "afterlife_transition" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_afterlife_transition" ); + level._effect[ "fx_alcatraz_ghost_vm_wrist" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_ghost_vm_wrist" ); + level._effect[ "fx_alcatraz_ghost_vm_wrist_r" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_ghost_vm_wrist_r" ); + level._effect[ "fx_alcatraz_ghost_spectate" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_ghost_spec" ); +} + +afterlife_start_zombie_logic() +{ + flag_wait( "start_zombie_round_logic" ); + wait 0,5; + b_everyone_alive = 0; + while ( isDefined( b_everyone_alive ) && !b_everyone_alive ) + { + b_everyone_alive = 1; + a_players = getplayers(); + _a192 = a_players; + _k192 = getFirstArrayKey( _a192 ); + while ( isDefined( _k192 ) ) + { + player = _a192[ _k192 ]; + if ( isDefined( player.afterlife ) && player.afterlife ) + { + b_everyone_alive = 0; + wait 0,05; + break; + } + else + { + _k192 = getNextArrayKey( _a192, _k192 ); + } + } + } + wait 0,5; + while ( level.intermission ) + { + wait 0,05; + } + flag_set( "afterlife_start_over" ); + wait 2; + array_func( getplayers(), ::afterlife_add ); +} + +is_player_valid_afterlife( player ) +{ + if ( isDefined( player.afterlife ) && player.afterlife ) + { + return 0; + } + return 1; +} + +can_revive_override( revivee ) +{ + if ( isDefined( self.afterlife ) && self.afterlife ) + { + return 0; + } + return 1; +} + +player_out_of_playable_area() +{ + if ( isDefined( self.afterlife ) && self.afterlife ) + { + return 0; + } + if ( isDefined( self.on_a_plane ) && self.on_a_plane ) + { + return 0; + } + return 1; +} + +init_player() +{ + flag_wait( "initial_players_connected" ); + if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game ) + { + self.lives = 3; + } + else + { + self.lives = 1; + } + self setclientfieldtoplayer( "player_lives", self.lives ); + self.afterlife = 0; + self.afterliferound = level.round_number; + self.afterlifedeaths = 0; + self thread afterlife_doors_close(); + self thread afterlife_player_refill_watch(); +} + +afterlife_remove( b_afterlife_death ) +{ + if ( !isDefined( b_afterlife_death ) ) + { + b_afterlife_death = 0; + } + if ( isDefined( b_afterlife_death ) && b_afterlife_death ) + { + self.lives = 0; + } + else + { + if ( self.lives > 0 ) + { + self.lives--; + + } + } + self notify( "sndLifeGone" ); + self setclientfieldtoplayer( "player_lives", self.lives ); +} + +afterlife_add() +{ + if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game ) + { + if ( self.lives < 3 ) + { + self.lives++; + self thread afterlife_add_fx(); + } + } + else + { + if ( self.lives < 1 ) + { + self.lives++; + self thread afterlife_add_fx(); + } + } + self playsoundtoplayer( "zmb_afterlife_add", self ); + self setclientfieldtoplayer( "player_lives", self.lives ); +} + +afterlife_add_fx() +{ + if ( isDefined( self.afterlife ) && !self.afterlife ) + { + self setclientfieldtoplayer( "player_afterlife_refill", 1 ); + wait 3; + if ( isDefined( self.afterlife ) && !self.afterlife ) + { + self setclientfieldtoplayer( "player_afterlife_refill", 0 ); + } + } +} + +afterlife_player_refill_watch() +{ + self endon( "disconnect" ); + self endon( "_zombie_game_over" ); + level endon( "stage_final" ); + while ( 1 ) + { + level waittill( "end_of_round" ); + wait 2; + self afterlife_add(); + reset_all_afterlife_unitriggers(); + } +} + +afterlife_player_damage_callback( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime ) +{ + if ( isDefined( eattacker ) ) + { + if ( isDefined( eattacker.is_zombie ) && eattacker.is_zombie ) + { + if ( isDefined( eattacker.custom_damage_func ) ) + { + idamage = eattacker [[ eattacker.custom_damage_func ]]( self ); + } + else + { + if ( isDefined( eattacker.meleedamage ) && smeansofdeath != "MOD_GRENADE_SPLASH" ) + { + idamage = eattacker.meleedamage; + } + } + if ( isDefined( self.afterlife ) && self.afterlife ) + { + self afterlife_reduce_mana( 10 ); + self clientnotify( "al_d" ); + return 0; + } + } + } + if ( isDefined( self.afterlife ) && self.afterlife ) + { + return 0; + } + if ( isDefined( eattacker ) && isDefined( eattacker.is_zombie ) || eattacker.is_zombie && isplayer( eattacker ) ) + { + if ( isDefined( self.hasriotshield ) && self.hasriotshield && isDefined( vdir ) ) + { + item_dmg = 100; + if ( isDefined( eattacker.custom_item_dmg ) ) + { + item_dmg = eattacker.custom_item_dmg; + } + if ( isDefined( self.hasriotshieldequipped ) && self.hasriotshieldequipped ) + { + if ( self player_shield_facing_attacker( vdir, 0,2 ) && isDefined( self.player_shield_apply_damage ) ) + { + self [[ self.player_shield_apply_damage ]]( item_dmg, 0 ); + return 0; + } + } + else + { + if ( !isDefined( self.riotshieldentity ) ) + { + if ( !self player_shield_facing_attacker( vdir, -0,2 ) && isDefined( self.player_shield_apply_damage ) ) + { + self [[ self.player_shield_apply_damage ]]( item_dmg, 0 ); + return 0; + } + } + } + } + } + if ( smeansofdeath != "MOD_PROJECTILE" && smeansofdeath != "MOD_PROJECTILE_SPLASH" || smeansofdeath == "MOD_GRENADE" && smeansofdeath == "MOD_GRENADE_SPLASH" ) + { + if ( sweapon == "blundersplat_explosive_dart_zm" ) + { + if ( self hasperk( "specialty_flakjacket" ) ) + { + self.use_adjusted_grenade_damage = 1; + idamage = 0; + } + if ( isalive( self ) && isDefined( self.is_zombie ) && !self.is_zombie ) + { + self.use_adjusted_grenade_damage = 1; + idamage = 10; + } + } + else + { + if ( self hasperk( "specialty_flakjacket" ) ) + { + return 0; + } + if ( self.health > 75 && isDefined( self.is_zombie ) && !self.is_zombie ) + { + idamage = 75; + } + } + } + if ( sweapon == "tower_trap_zm" || sweapon == "tower_trap_upgraded_zm" ) + { + self.use_adjusted_grenade_damage = 1; + return 0; + } + if ( idamage >= self.health && isDefined( level.intermission ) && !level.intermission ) + { + if ( self.lives > 0 && isDefined( self.afterlife ) && !self.afterlife ) + { + self playsoundtoplayer( "zmb_afterlife_death", self ); + self afterlife_remove(); + self.afterlife = 1; + self thread afterlife_laststand(); + if ( self.health <= 1 ) + { + return 0; + } + else + { + idamage = self.health - 1; + } + } + else + { + self thread last_stand_conscience_vo(); + } + } + return idamage; +} + +afterlife_enter() +{ + if ( !isDefined( self.afterlife_visionset ) || self.afterlife_visionset == 0 ) + { + maps/mp/_visionset_mgr::vsmgr_activate( "visionset", "zm_afterlife", self ); + if ( isDefined( level.optimise_for_splitscreen ) && !level.optimise_for_splitscreen ) + { + maps/mp/_visionset_mgr::vsmgr_activate( "overlay", "zm_afterlife_filter", self ); + } + self.afterlife_visionset = 1; + } + self enableafterlife(); + self.str_living_model = self.model; + self.str_living_view = self getviewmodel(); + self setmodel( "c_zom_hero_ghost_fb" ); + self setviewmodel( "c_zom_ghost_viewhands" ); + self thread afterlife_doors_open(); + self setclientfieldtoplayer( "player_in_afterlife", 1 ); + self setclientfield( "player_afterlife_fx", 1 ); + self afterlife_create_mana_bar( self.e_afterlife_corpse ); + if ( !isDefined( self.keep_perks ) && flag( "afterlife_start_over" ) ) + { + self increment_downed_stat(); + } + a_afterlife_triggers = getstructarray( "afterlife_trigger", "targetname" ); + _a534 = a_afterlife_triggers; + _k534 = getFirstArrayKey( _a534 ); + while ( isDefined( _k534 ) ) + { + struct = _a534[ _k534 ]; + struct.unitrigger_stub maps/mp/zombies/_zm_unitrigger::run_visibility_function_for_all_triggers(); + _k534 = getNextArrayKey( _a534, _k534 ); + } + a_exterior_goals = getstructarray( "exterior_goal", "targetname" ); + _a541 = a_exterior_goals; + _k541 = getFirstArrayKey( _a541 ); + while ( isDefined( _k541 ) ) + { + struct = _a541[ _k541 ]; + if ( isDefined( struct.unitrigger_stub ) ) + { + struct.unitrigger_stub maps/mp/zombies/_zm_unitrigger::run_visibility_function_for_all_triggers(); + } + _k541 = getNextArrayKey( _a541, _k541 ); + } +} + +afterlife_leave( b_revived ) +{ + if ( !isDefined( b_revived ) ) + { + b_revived = 1; + } + self clientnotify( "al_t" ); + if ( isDefined( self.afterlife_visionset ) && self.afterlife_visionset ) + { + maps/mp/_visionset_mgr::vsmgr_deactivate( "visionset", "zm_afterlife", self ); + if ( isDefined( level.optimise_for_splitscreen ) && !level.optimise_for_splitscreen ) + { + maps/mp/_visionset_mgr::vsmgr_deactivate( "overlay", "zm_afterlife_filter", self ); + } + self.afterlife_visionset = 0; + } + self disableafterlife(); + self.dontspeak = 0; + self thread afterlife_doors_close(); + self.health = self.maxhealth; + self setclientfieldtoplayer( "player_in_afterlife", 0 ); + self setclientfield( "player_afterlife_fx", 0 ); + self setclientfieldtoplayer( "clientfield_afterlife_audio", 0 ); + self maps/mp/zombies/_zm_perks::perk_set_max_health_if_jugg( "health_reboot", 1, 0 ); + self allowstand( 1 ); + self allowcrouch( 1 ); + self allowprone( 1 ); + self setmodel( self.str_living_model ); + self setviewmodel( self.str_living_view ); + if ( self.e_afterlife_corpse.revivetrigger.origin != self.e_afterlife_corpse.origin ) + { + self setorigin( self.e_afterlife_corpse.revivetrigger.origin ); + } + else + { + self setorigin( self.e_afterlife_corpse.origin ); + } + while ( isDefined( level.e_gondola ) ) + { + a_gondola_doors_gates = get_gondola_doors_and_gates(); + i = 0; + while ( i < a_gondola_doors_gates.size ) + { + if ( self.e_afterlife_corpse istouching( a_gondola_doors_gates[ i ] ) ) + { + if ( isDefined( level.e_gondola.is_moving ) && level.e_gondola.is_moving ) + { + str_location = level.e_gondola.destination; + } + else + { + str_location = level.e_gondola.location; + } + a_s_orgs = getstructarray( "gondola_dropped_parts_" + str_location, "targetname" ); + _a617 = a_s_orgs; + _k617 = getFirstArrayKey( _a617 ); + while ( isDefined( _k617 ) ) + { + struct = _a617[ _k617 ]; + if ( !positionwouldtelefrag( struct.origin ) ) + { + self setorigin( struct.origin ); + break; + } + else + { + _k617 = getNextArrayKey( _a617, _k617 ); + } + } + } + else i++; + } + } + self setplayerangles( self.e_afterlife_corpse.angles ); + self.afterlife = 0; + self afterlife_laststand_cleanup( self.e_afterlife_corpse ); + if ( isDefined( b_revived ) && !b_revived ) + { + self afterlife_remove( 1 ); + self dodamage( 1000, self.origin ); + } + reset_all_afterlife_unitriggers(); +} + +afterlife_laststand( b_electric_chair ) +{ + if ( !isDefined( b_electric_chair ) ) + { + b_electric_chair = 0; + } + self endon( "disconnect" ); + self endon( "afterlife_bleedout" ); + level endon( "end_game" ); + if ( isDefined( level.afterlife_laststand_override ) ) + { + self thread [[ level.afterlife_laststand_override ]]( b_electric_chair ); + return; + } + self.dontspeak = 1; + self.health = 1000; + b_has_electric_cherry = 0; + if ( self hasperk( "specialty_grenadepulldeath" ) ) + { + b_has_electric_cherry = 1; + } + self [[ level.afterlife_save_loadout ]](); + self afterlife_fake_death(); + if ( isDefined( b_electric_chair ) && !b_electric_chair ) + { + wait 1; + } + if ( isDefined( b_has_electric_cherry ) && b_has_electric_cherry && isDefined( b_electric_chair ) && !b_electric_chair ) + { + self maps/mp/zombies/_zm_perk_electric_cherry::electric_cherry_laststand(); + wait 2; + } + self setclientfieldtoplayer( "clientfield_afterlife_audio", 1 ); + if ( flag( "afterlife_start_over" ) ) + { + self clientnotify( "al_t" ); + wait 1; + self thread fadetoblackforxsec( 0, 1, 0,5, 0,5, "white" ); + wait 0,5; + } + self ghost(); + self.e_afterlife_corpse = self afterlife_spawn_corpse(); + self thread afterlife_clean_up_on_disconnect(); + self notify( "player_fake_corpse_created" ); + self afterlife_fake_revive(); + self afterlife_enter(); + self.e_afterlife_corpse setclientfield( "player_corpse_id", self getentitynumber() + 1 ); + wait 0,5; + self show(); + if ( isDefined( self.hostmigrationcontrolsfrozen ) && !self.hostmigrationcontrolsfrozen ) + { + self freezecontrols( 0 ); + } + self disableinvulnerability(); + self.e_afterlife_corpse waittill( "player_revived", e_reviver ); + self notify( "player_revived" ); + self seteverhadweaponall( 1 ); + self enableinvulnerability(); + self.afterlife_revived = 1; + playsoundatposition( "zmb_afterlife_spawn_leave", self.e_afterlife_corpse.origin ); + self afterlife_leave(); + self thread afterlife_revive_invincible(); + self playsound( "zmb_afterlife_revived_gasp" ); +} + +afterlife_clean_up_on_disconnect() +{ + e_corpse = self.e_afterlife_corpse; + e_corpse endon( "death" ); + self waittill( "disconnect" ); + if ( isDefined( e_corpse.revivetrigger ) ) + { + e_corpse notify( "stop_revive_trigger" ); + e_corpse.revivetrigger delete(); + e_corpse.revivetrigger = undefined; + } + e_corpse setclientfield( "player_corpse_id", 0 ); + e_corpse notify( "disconnect" ); + wait_network_frame(); + wait_network_frame(); + e_corpse delete(); +} + +afterlife_revive_invincible() +{ + self endon( "disconnect" ); + wait 2; + self disableinvulnerability(); + self seteverhadweaponall( 0 ); + self.afterlife_revived = undefined; +} + +afterlife_laststand_cleanup( corpse ) +{ + self [[ level.afterlife_give_loadout ]](); + self afterlife_corpse_cleanup( corpse ); +} + +afterlife_create_mana_bar( corpse ) +{ + if ( self.afterliferound == level.round_number ) + { + if ( !isDefined( self.keep_perks ) || self.afterlifedeaths == 0 ) + { + self.afterlifedeaths++; + } + } + else + { + self.afterliferound = level.round_number; + self.afterlifedeaths = 1; + } + self.manacur = 200; + self thread afterlife_mana_watch( corpse ); + self thread afterlife_lightning_watch( corpse ); + self thread afterlife_jump_watch( corpse ); +} + +afterlife_infinite_mana( b_infinite ) +{ + if ( !isDefined( b_infinite ) ) + { + b_infinite = 1; + } + if ( isDefined( b_infinite ) && b_infinite ) + { + self.infinite_mana = 1; + } + else + { + self.infinite_mana = 0; + } +} + +afterlife_mana_watch( corpse ) +{ + self endon( "disconnect" ); + corpse endon( "player_revived" ); + while ( self.manacur > 0 ) + { + wait 0,05; + self afterlife_reduce_mana( 0,05 * self.afterlifedeaths * 3 ); + if ( self.manacur < 0 ) + { + self.manacur = 0; + } + n_mapped_mana = linear_map( self.manacur, 0, 200, 0, 1 ); + self setclientfieldtoplayer( "player_afterlife_mana", n_mapped_mana ); + } + while ( isDefined( corpse.revivetrigger ) ) + { + while ( corpse.revivetrigger.beingrevived ) + { + wait 0,05; + } + } + corpse notify( "stop_revive_trigger" ); + self thread fadetoblackforxsec( 0, 0,5, 0,5, 0,5, "black" ); + wait 0,5; + self notify( "out_of_mana" ); + self afterlife_leave( 0 ); +} + +afterlife_doors_open() +{ + n_network_sent = 0; + a_show = getentarray( "afterlife_show", "targetname" ); + a_show = arraycombine( a_show, getentarray( "afterlife_prop", "script_noteworthy" ), 0, 0 ); + _a888 = a_show; + _k888 = getFirstArrayKey( _a888 ); + while ( isDefined( _k888 ) ) + { + ent = _a888[ _k888 ]; + n_network_sent++; + if ( n_network_sent > 10 ) + { + n_network_sent = 0; + wait_network_frame(); + } + if ( isDefined( ent ) ) + { + ent setvisibletoplayer( self ); + } + _k888 = getNextArrayKey( _a888, _k888 ); + } + a_hide = getentarray( "afterlife_door", "targetname" ); + a_hide = arraycombine( a_hide, getentarray( "zombie_door", "targetname" ), 0, 0 ); + a_hide = arraycombine( a_hide, getentarray( "quest_trigger", "script_noteworthy" ), 0, 0 ); + a_hide = arraycombine( a_hide, getentarray( "trap_trigger", "script_noteworthy" ), 0, 0 ); + a_hide = arraycombine( a_hide, getentarray( "travel_trigger", "script_noteworthy" ), 0, 0 ); + _a907 = a_hide; + _k907 = getFirstArrayKey( _a907 ); + while ( isDefined( _k907 ) ) + { + ent = _a907[ _k907 ]; + n_network_sent++; + if ( n_network_sent > 10 ) + { + n_network_sent = 0; + wait_network_frame(); + } + if ( isDefined( ent ) ) + { + ent setinvisibletoplayer( self ); + } + _k907 = getNextArrayKey( _a907, _k907 ); + } + while ( isDefined( self.claymores ) ) + { + _a924 = self.claymores; + _k924 = getFirstArrayKey( _a924 ); + while ( isDefined( _k924 ) ) + { + claymore = _a924[ _k924 ]; + if ( isDefined( claymore.pickuptrigger ) ) + { + claymore.pickuptrigger setinvisibletoplayer( self ); + } + _k924 = getNextArrayKey( _a924, _k924 ); + } + } +} + +afterlife_doors_close() +{ + n_network_sent = 0; + a_hide = getentarray( "afterlife_show", "targetname" ); + a_hide = arraycombine( a_hide, getentarray( "afterlife_prop", "script_noteworthy" ), 0, 0 ); + _a943 = a_hide; + _k943 = getFirstArrayKey( _a943 ); + while ( isDefined( _k943 ) ) + { + ent = _a943[ _k943 ]; + n_network_sent++; + if ( n_network_sent > 10 ) + { + n_network_sent = 0; + wait_network_frame(); + } + if ( isDefined( ent ) ) + { + ent setinvisibletoplayer( self ); + } + _k943 = getNextArrayKey( _a943, _k943 ); + } + a_show = getentarray( "afterlife_door", "targetname" ); + a_show = arraycombine( a_show, getentarray( "zombie_door", "targetname" ), 0, 0 ); + a_show = arraycombine( a_show, getentarray( "quest_trigger", "script_noteworthy" ), 0, 0 ); + a_show = arraycombine( a_show, getentarray( "trap_trigger", "script_noteworthy" ), 0, 0 ); + a_show = arraycombine( a_show, getentarray( "travel_trigger", "script_noteworthy" ), 0, 0 ); + _a962 = a_show; + _k962 = getFirstArrayKey( _a962 ); + while ( isDefined( _k962 ) ) + { + ent = _a962[ _k962 ]; + n_network_sent++; + if ( n_network_sent > 10 ) + { + n_network_sent = 0; + wait_network_frame(); + } + if ( isDefined( ent ) ) + { + ent setvisibletoplayer( self ); + } + _k962 = getNextArrayKey( _a962, _k962 ); + } + while ( isDefined( self.claymores ) ) + { + _a979 = self.claymores; + _k979 = getFirstArrayKey( _a979 ); + while ( isDefined( _k979 ) ) + { + claymore = _a979[ _k979 ]; + if ( isDefined( claymore.pickuptrigger ) ) + { + claymore.pickuptrigger setvisibletoplayer( self ); + } + _k979 = getNextArrayKey( _a979, _k979 ); + } + } +} + +afterlife_corpse_cleanup( corpse ) +{ + playsoundatposition( "zmb_afterlife_revived", corpse.origin ); + if ( isDefined( corpse.revivetrigger ) ) + { + corpse notify( "stop_revive_trigger" ); + corpse.revivetrigger delete(); + corpse.revivetrigger = undefined; + } + corpse setclientfield( "player_corpse_id", 0 ); + corpse afterlife_corpse_remove_pois(); + wait_network_frame(); + wait_network_frame(); + corpse delete(); + self.e_afterlife_corpse = undefined; +} + +afterlife_spawn_corpse() +{ + if ( isDefined( self.is_on_gondola ) && self.is_on_gondola && level.e_gondola.destination == "roof" ) + { + corpse = maps/mp/zombies/_zm_clone::spawn_player_clone( self, self.origin, undefined ); + } + else + { + trace_start = self.origin; + trace_end = self.origin + vectorScale( ( 0, 0, 1 ), 500 ); + corpse_trace = playerphysicstrace( trace_start, trace_end ); + corpse = maps/mp/zombies/_zm_clone::spawn_player_clone( self, corpse_trace, undefined ); + } + corpse.angles = self.angles; + corpse.ignoreme = 1; + corpse maps/mp/zombies/_zm_clone::clone_give_weapon( "m1911_zm" ); + corpse maps/mp/zombies/_zm_clone::clone_animate( "afterlife" ); + corpse.revive_hud = self afterlife_revive_hud_create(); + corpse thread afterlife_revive_trigger_spawn(); + if ( flag( "solo_game" ) ) + { + corpse thread afterlife_corpse_create_pois(); + } + return corpse; +} + +afterlife_corpse_create_pois() +{ + n_attractors = ceil( get_current_zombie_count() / 3 ); + if ( n_attractors < 4 ) + { + n_attractors = 4; + } + a_nodes = afterlife_corpse_get_array_poi_positions(); + self.pois = []; + while ( isDefined( a_nodes ) && a_nodes.size > 3 ) + { + i = 0; + while ( i < 3 ) + { + self.pois[ i ] = afterlife_corpse_create_poi( a_nodes[ i ].origin, n_attractors ); + wait 0,05; + i++; + } + } +} + +afterlife_corpse_create_poi( v_origin, n_attractors ) +{ + e_poi = spawn( "script_origin", v_origin ); + e_poi create_zombie_point_of_interest( 10000, 24, 5000, 1 ); + e_poi thread create_zombie_point_of_interest_attractor_positions(); +/# + e_poi thread print3d_ent( "Corpse POI" ); +#/ + return e_poi; +} + +afterlife_corpse_remove_pois() +{ + if ( !isDefined( self.pois ) ) + { + return; + } + i = 0; + while ( i < self.pois.size ) + { + remove_poi_attractor( self.pois[ i ] ); + self.pois[ i ] delete(); + i++; + } + self.pois = undefined; +} + +afterlife_corpse_get_array_poi_positions() +{ + n_ideal_dist_sq = 490000; + a_nodes = getanynodearray( self.origin, 1200 ); + i = 0; + while ( i < a_nodes.size ) + { + if ( !a_nodes[ i ] is_valid_teleport_node() ) + { + } + i++; + } + a_nodes = remove_undefined_from_array( a_nodes ); + return array_randomize( a_nodes ); +} + +afterlife_revive_hud_create() +{ + self.revive_hud = newclienthudelem( self ); + self.revive_hud.alignx = "center"; + self.revive_hud.aligny = "middle"; + self.revive_hud.horzalign = "center"; + self.revive_hud.vertalign = "bottom"; + self.revive_hud.y = -160; + self.revive_hud.foreground = 1; + self.revive_hud.font = "default"; + self.revive_hud.fontscale = 1,5; + self.revive_hud.alpha = 0; + self.revive_hud.color = ( 0, 0, 1 ); + self.revive_hud.hidewheninmenu = 1; + self.revive_hud settext( "" ); + return self.revive_hud; +} + +afterlife_revive_trigger_spawn() +{ + radius = getDvarInt( "revive_trigger_radius" ); + self.revivetrigger = spawn( "trigger_radius", ( 0, 0, 1 ), 0, radius, radius ); + self.revivetrigger sethintstring( "" ); + self.revivetrigger setcursorhint( "HINT_NOICON" ); + self.revivetrigger setmovingplatformenabled( 1 ); + self.revivetrigger enablelinkto(); + self.revivetrigger.origin = self.origin; + self.revivetrigger linkto( self ); + self.revivetrigger.beingrevived = 0; + self.revivetrigger.createtime = getTime(); + self thread afterlife_revive_trigger_think(); +} + +afterlife_revive_trigger_think() +{ + self endon( "disconnect" ); + self endon( "stop_revive_trigger" ); + self endon( "death" ); + wait 1; + while ( 1 ) + { + wait 0,1; + self.revivetrigger sethintstring( "" ); + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ] afterlife_can_revive( self ) ) + { + self.revivetrigger setrevivehintstring( &"GAME_BUTTON_TO_REVIVE_PLAYER", self.team ); + break; + } + else + { + i++; + } + } + i = 0; + while ( i < players.size ) + { + reviver = players[ i ]; + if ( self == reviver || !reviver is_reviving_afterlife( self ) ) + { + i++; + continue; + } + else + { + gun = reviver getcurrentweapon(); +/# + assert( isDefined( gun ) ); +#/ + if ( gun == level.revive_tool || gun == level.afterlife_revive_tool ) + { + i++; + continue; + } + else + { + if ( isDefined( reviver.afterlife ) && reviver.afterlife ) + { + reviver giveweapon( level.afterlife_revive_tool ); + reviver switchtoweapon( level.afterlife_revive_tool ); + reviver setweaponammostock( level.afterlife_revive_tool, 1 ); + } + else + { + reviver giveweapon( level.revive_tool ); + reviver switchtoweapon( level.revive_tool ); + reviver setweaponammostock( level.revive_tool, 1 ); + } + revive_success = reviver afterlife_revive_do_revive( self, gun ); + reviver revive_give_back_weapons( gun ); + if ( isplayer( self ) ) + { + self allowjump( 1 ); + } + self.laststand = undefined; + if ( revive_success ) + { + self thread revive_success( reviver ); + self cleanup_suicide_hud(); + return; + } + } + } + i++; + } + } +} + +afterlife_can_revive( revivee ) +{ + if ( isDefined( self.afterlife ) && self.afterlife && isDefined( self.e_afterlife_corpse ) && self.e_afterlife_corpse != revivee ) + { + return 0; + } + if ( !isDefined( revivee.revivetrigger ) ) + { + return 0; + } + if ( !isalive( self ) ) + { + return 0; + } + if ( self player_is_in_laststand() ) + { + return 0; + } + if ( self.team != revivee.team ) + { + return 0; + } + if ( self has_powerup_weapon() ) + { + return 0; + } + ignore_sight_checks = 0; + ignore_touch_checks = 0; + if ( isDefined( level.revive_trigger_should_ignore_sight_checks ) ) + { + ignore_sight_checks = [[ level.revive_trigger_should_ignore_sight_checks ]]( self ); + if ( ignore_sight_checks && isDefined( revivee.revivetrigger.beingrevived ) && revivee.revivetrigger.beingrevived == 1 ) + { + ignore_touch_checks = 1; + } + } + if ( !ignore_touch_checks ) + { + if ( !self istouching( revivee.revivetrigger ) ) + { + return 0; + } + } + if ( !ignore_sight_checks ) + { + if ( !self is_facing( revivee ) ) + { + return 0; + } + if ( !sighttracepassed( self.origin + vectorScale( ( 0, 0, 1 ), 50 ), revivee.origin + vectorScale( ( 0, 0, 1 ), 30 ), 0, undefined ) ) + { + return 0; + } + } + return 1; +} + +afterlife_revive_do_revive( playerbeingrevived, revivergun ) +{ +/# + assert( self is_reviving_afterlife( playerbeingrevived ) ); +#/ + revivetime = 3; + playloop = 0; + if ( isDefined( self.afterlife ) && self.afterlife ) + { + playloop = 1; + revivetime = 1; + } + timer = 0; + revived = 0; + playerbeingrevived.revivetrigger.beingrevived = 1; + playerbeingrevived.revive_hud settext( &"GAME_PLAYER_IS_REVIVING_YOU", self ); + playerbeingrevived revive_hud_show_n_fade( 3 ); + playerbeingrevived.revivetrigger sethintstring( "" ); + if ( isplayer( playerbeingrevived ) ) + { + playerbeingrevived startrevive( self ); + } + if ( !isDefined( self.reviveprogressbar ) ) + { + self.reviveprogressbar = self createprimaryprogressbar(); + } + if ( !isDefined( self.revivetexthud ) ) + { + self.revivetexthud = newclienthudelem( self ); + } + self thread revive_clean_up_on_gameover(); + self thread laststand_clean_up_on_disconnect( playerbeingrevived, revivergun ); + if ( !isDefined( self.is_reviving_any ) ) + { + self.is_reviving_any = 0; + } + self.is_reviving_any++; + self thread laststand_clean_up_reviving_any( playerbeingrevived ); + self.reviveprogressbar updatebar( 0,01, 1 / revivetime ); + self.revivetexthud.alignx = "center"; + self.revivetexthud.aligny = "middle"; + self.revivetexthud.horzalign = "center"; + self.revivetexthud.vertalign = "bottom"; + self.revivetexthud.y = -113; + if ( self issplitscreen() ) + { + self.revivetexthud.y = -347; + } + self.revivetexthud.foreground = 1; + self.revivetexthud.font = "default"; + self.revivetexthud.fontscale = 1,8; + self.revivetexthud.alpha = 1; + self.revivetexthud.color = ( 0, 0, 1 ); + self.revivetexthud.hidewheninmenu = 1; + if ( isDefined( self.pers_upgrades_awarded[ "revive" ] ) && self.pers_upgrades_awarded[ "revive" ] ) + { + self.revivetexthud.color = ( 0,5, 0,5, 1 ); + } + self.revivetexthud settext( &"GAME_REVIVING" ); + self thread check_for_failed_revive( playerbeingrevived ); + e_fx = spawn( "script_model", playerbeingrevived.revivetrigger.origin ); + e_fx setmodel( "tag_origin" ); + e_fx thread revive_fx_clean_up_on_disconnect( playerbeingrevived ); + playfxontag( level._effect[ "afterlife_leave" ], e_fx, "tag_origin" ); + if ( isDefined( playloop ) && playloop ) + { + e_fx playloopsound( "zmb_afterlife_reviving", 0,05 ); + } + while ( self is_reviving_afterlife( playerbeingrevived ) ) + { + wait 0,05; + timer += 0,05; + if ( self player_is_in_laststand() ) + { + break; + } + else if ( isDefined( playerbeingrevived.revivetrigger.auto_revive ) && playerbeingrevived.revivetrigger.auto_revive == 1 ) + { + break; + } + else + { + if ( timer >= revivetime ) + { + revived = 1; + break; + } + else + { + } + } + } + e_fx delete(); + if ( isDefined( self.reviveprogressbar ) ) + { + self.reviveprogressbar destroyelem(); + } + if ( isDefined( self.revivetexthud ) ) + { + self.revivetexthud destroy(); + } + if ( isDefined( playerbeingrevived.revivetrigger.auto_revive ) && playerbeingrevived.revivetrigger.auto_revive == 1 ) + { + } + else if ( !revived ) + { + if ( isplayer( playerbeingrevived ) ) + { + playerbeingrevived stoprevive( self ); + } + } + playerbeingrevived.revivetrigger sethintstring( &"GAME_BUTTON_TO_REVIVE_PLAYER" ); + playerbeingrevived.revivetrigger.beingrevived = 0; + self notify( "do_revive_ended_normally" ); + self.is_reviving_any--; + + if ( !revived ) + { + playerbeingrevived thread checkforbleedout( self ); + } + return revived; +} + +revive_fx_clean_up_on_disconnect( e_corpse ) +{ + self endon( "death" ); + e_corpse waittill( "disconnect" ); + self delete(); +} + +revive_clean_up_on_gameover() +{ + self endon( "do_revive_ended_normally" ); + level waittill( "end_game" ); + if ( isDefined( self.reviveprogressbar ) ) + { + self.reviveprogressbar destroyelem(); + } + if ( isDefined( self.revivetexthud ) ) + { + self.revivetexthud destroy(); + } +} + +is_reviving_afterlife( revivee ) +{ + if ( self usebuttonpressed() ) + { + return afterlife_can_revive( revivee ); + } +} + +afterlife_save_loadout() +{ + primaries = self getweaponslistprimaries(); + currentweapon = self getcurrentweapon(); + self.loadout = spawnstruct(); + self.loadout.player = self; + self.loadout.weapons = []; + self.loadout.score = self.score; + self.loadout.current_weapon = 0; + _a1516 = primaries; + index = getFirstArrayKey( _a1516 ); + while ( isDefined( index ) ) + { + weapon = _a1516[ index ]; + self.loadout.weapons[ index ] = weapon; + self.loadout.stockcount[ index ] = self getweaponammostock( weapon ); + self.loadout.clipcount[ index ] = self getweaponammoclip( weapon ); + if ( weaponisdualwield( weapon ) ) + { + weapon_dw = weapondualwieldweaponname( weapon ); + self.loadout.clipcount2[ index ] = self getweaponammoclip( weapon_dw ); + } + weapon_alt = weaponaltweaponname( weapon ); + if ( weapon_alt != "none" ) + { + self.loadout.stockcountalt[ index ] = self getweaponammostock( weapon_alt ); + self.loadout.clipcountalt[ index ] = self getweaponammoclip( weapon_alt ); + } + if ( weapon == currentweapon ) + { + self.loadout.current_weapon = index; + } + index = getNextArrayKey( _a1516, index ); + } + self.loadout.equipment = self get_player_equipment(); + if ( isDefined( self.loadout.equipment ) ) + { + self equipment_take( self.loadout.equipment ); + } + if ( self hasweapon( "claymore_zm" ) ) + { + self.loadout.hasclaymore = 1; + self.loadout.claymoreclip = self getweaponammoclip( "claymore_zm" ); + } + if ( self hasweapon( "emp_grenade_zm" ) ) + { + self.loadout.hasemp = 1; + self.loadout.empclip = self getweaponammoclip( "emp_grenade_zm" ); + } + if ( self hasweapon( "bouncing_tomahawk_zm" ) || self hasweapon( "upgraded_tomahawk_zm" ) ) + { + self.loadout.hastomahawk = 1; + self setclientfieldtoplayer( "tomahawk_in_use", 0 ); + } + self.loadout.perks = afterlife_save_perks( self ); + lethal_grenade = self get_player_lethal_grenade(); + if ( self hasweapon( lethal_grenade ) ) + { + self.loadout.grenade = self getweaponammoclip( lethal_grenade ); + } + else + { + self.loadout.grenade = 0; + } + self.loadout.lethal_grenade = lethal_grenade; + self set_player_lethal_grenade( undefined ); +} + +afterlife_give_loadout() +{ + self takeallweapons(); + loadout = self.loadout; + primaries = self getweaponslistprimaries(); + while ( loadout.weapons.size > 1 || primaries.size > 1 ) + { + _a1601 = primaries; + _k1601 = getFirstArrayKey( _a1601 ); + while ( isDefined( _k1601 ) ) + { + weapon = _a1601[ _k1601 ]; + self takeweapon( weapon ); + _k1601 = getNextArrayKey( _a1601, _k1601 ); + } + } + i = 0; + while ( i < loadout.weapons.size ) + { + if ( !isDefined( loadout.weapons[ i ] ) ) + { + i++; + continue; + } + else if ( loadout.weapons[ i ] == "none" ) + { + i++; + continue; + } + else + { + weapon = loadout.weapons[ i ]; + stock_amount = loadout.stockcount[ i ]; + clip_amount = loadout.clipcount[ i ]; + if ( !self hasweapon( weapon ) ) + { + self giveweapon( weapon, 0, self maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( weapon ) ); + self setweaponammostock( weapon, stock_amount ); + self setweaponammoclip( weapon, clip_amount ); + if ( weaponisdualwield( weapon ) ) + { + weapon_dw = weapondualwieldweaponname( weapon ); + self setweaponammoclip( weapon_dw, loadout.clipcount2[ i ] ); + } + weapon_alt = weaponaltweaponname( weapon ); + if ( weapon_alt != "none" ) + { + self setweaponammostock( weapon_alt, loadout.stockcountalt[ i ] ); + self setweaponammoclip( weapon_alt, loadout.clipcountalt[ i ] ); + } + } + } + i++; + } + self setspawnweapon( loadout.weapons[ loadout.current_weapon ] ); + self switchtoweaponimmediate( loadout.weapons[ loadout.current_weapon ] ); + if ( isDefined( self get_player_melee_weapon() ) ) + { + self giveweapon( self get_player_melee_weapon() ); + } + self maps/mp/zombies/_zm_equipment::equipment_give( self.loadout.equipment ); + if ( isDefined( loadout.hasclaymore ) && loadout.hasclaymore && !self hasweapon( "claymore_zm" ) ) + { + self giveweapon( "claymore_zm" ); + self set_player_placeable_mine( "claymore_zm" ); + self setactionslot( 4, "weapon", "claymore_zm" ); + self setweaponammoclip( "claymore_zm", loadout.claymoreclip ); + } + if ( isDefined( loadout.hasemp ) && loadout.hasemp ) + { + self giveweapon( "emp_grenade_zm" ); + self setweaponammoclip( "emp_grenade_zm", loadout.empclip ); + } + if ( isDefined( loadout.hastomahawk ) && loadout.hastomahawk ) + { + self giveweapon( self.current_tomahawk_weapon ); + self set_player_tactical_grenade( self.current_tomahawk_weapon ); + self setclientfieldtoplayer( "tomahawk_in_use", 1 ); + } + self.score = loadout.score; + perk_array = maps/mp/zombies/_zm_perks::get_perk_array( 1 ); + i = 0; + while ( i < perk_array.size ) + { + perk = perk_array[ i ]; + self unsetperk( perk ); + self set_perk_clientfield( perk, 0 ); + i++; + } + while ( isDefined( self.keep_perks ) && self.keep_perks && isDefined( loadout.perks ) && loadout.perks.size > 0 ) + { + i = 0; + while ( i < loadout.perks.size ) + { + if ( self hasperk( loadout.perks[ i ] ) ) + { + i++; + continue; + } + else if ( loadout.perks[ i ] == "specialty_quickrevive" && flag( "solo_game" ) ) + { + level.solo_game_free_player_quickrevive = 1; + } + if ( loadout.perks[ i ] == "specialty_finalstand" ) + { + i++; + continue; + } + else + { + maps/mp/zombies/_zm_perks::give_perk( loadout.perks[ i ] ); + } + i++; + } + } + self.keep_perks = undefined; + self set_player_lethal_grenade( self.loadout.lethal_grenade ); + if ( loadout.grenade > 0 ) + { + curgrenadecount = 0; + if ( self hasweapon( self get_player_lethal_grenade() ) ) + { + self getweaponammoclip( self get_player_lethal_grenade() ); + } + else + { + self giveweapon( self get_player_lethal_grenade() ); + } + self setweaponammoclip( self get_player_lethal_grenade(), loadout.grenade + curgrenadecount ); + } +} + +afterlife_fake_death() +{ + level notify( "fake_death" ); + self notify( "fake_death" ); + self takeallweapons(); + self allowstand( 0 ); + self allowcrouch( 0 ); + self allowprone( 1 ); + self setstance( "prone" ); + while ( self is_jumping() ) + { + while ( self is_jumping() ) + { + wait 0,05; + } + } + playfx( level._effect[ "afterlife_enter" ], self.origin ); + self.ignoreme = 1; + self enableinvulnerability(); + self freezecontrols( 1 ); +} + +afterlife_fake_revive() +{ + level notify( "fake_revive" ); + self notify( "fake_revive" ); + playsoundatposition( "zmb_afterlife_spawn_leave", self.origin ); + if ( flag( "afterlife_start_over" ) ) + { + spawnpoint = [[ level.afterlife_get_spawnpoint ]](); + trace_start = spawnpoint.origin; + trace_end = spawnpoint.origin + vectorScale( ( 0, 0, 1 ), 200 ); + respawn_trace = playerphysicstrace( trace_start, trace_end ); + self setorigin( respawn_trace ); + self setplayerangles( spawnpoint.angles ); + playsoundatposition( "zmb_afterlife_spawn_enter", spawnpoint.origin ); + } + else + { + playsoundatposition( "zmb_afterlife_spawn_enter", self.origin ); + } + self allowstand( 1 ); + self allowcrouch( 0 ); + self allowprone( 0 ); + self.ignoreme = 0; + self setstance( "stand" ); + self giveweapon( "lightning_hands_zm" ); + self switchtoweapon( "lightning_hands_zm" ); + self.score = 0; + wait 1; +} + +afterlife_get_spawnpoint() +{ + spawnpoint = check_for_valid_spawn_in_zone( self ); + if ( !isDefined( spawnpoint ) ) + { + spawnpoint = maps/mp/zombies/_zm::check_for_valid_spawn_near_position( self, self.origin, 1 ); + } + if ( !isDefined( spawnpoint ) ) + { + spawnpoint = maps/mp/zombies/_zm::check_for_valid_spawn_near_team( self, 1 ); + } + if ( !isDefined( spawnpoint ) ) + { + match_string = ""; + location = level.scr_zm_map_start_location; + if ( location != "default" && location == "" && isDefined( level.default_start_location ) ) + { + location = level.default_start_location; + } + match_string = ( level.scr_zm_ui_gametype + "_" ) + location; + spawnpoints = []; + structs = getstructarray( "initial_spawn", "script_noteworthy" ); + while ( isDefined( structs ) ) + { + _a1858 = structs; + _k1858 = getFirstArrayKey( _a1858 ); + while ( isDefined( _k1858 ) ) + { + struct = _a1858[ _k1858 ]; + while ( isDefined( struct.script_string ) ) + { + tokens = strtok( struct.script_string, " " ); + _a1864 = tokens; + _k1864 = getFirstArrayKey( _a1864 ); + while ( isDefined( _k1864 ) ) + { + token = _a1864[ _k1864 ]; + if ( token == match_string ) + { + spawnpoints[ spawnpoints.size ] = struct; + } + _k1864 = getNextArrayKey( _a1864, _k1864 ); + } + } + _k1858 = getNextArrayKey( _a1858, _k1858 ); + } + } + if ( !isDefined( spawnpoints ) || spawnpoints.size == 0 ) + { + spawnpoints = getstructarray( "initial_spawn_points", "targetname" ); + } +/# + assert( isDefined( spawnpoints ), "Could not find initial spawn points!" ); +#/ + spawnpoint = maps/mp/zombies/_zm::getfreespawnpoint( spawnpoints, self ); + } + return spawnpoint; +} + +check_for_valid_spawn_in_zone( player ) +{ + a_spawn_points = maps/mp/gametypes_zm/_zm_gametype::get_player_spawns_for_gametype(); + if ( isDefined( level.e_gondola ) && isDefined( level.e_gondola.is_moving ) && level.e_gondola.is_moving ) + { + if ( player maps/mp/zm_alcatraz_travel::is_player_on_gondola() ) + { + if ( level.e_gondola.destination == "roof" ) + { + str_player_zone = "zone_cellblock_west_gondola"; + } + else + { + if ( level.e_gondola.destination == "docks" ) + { + str_player_zone = "zone_dock"; + } + } + } + else + { + str_player_zone = player maps/mp/zombies/_zm_zonemgr::get_player_zone(); + } + } + else + { + str_player_zone = player maps/mp/zombies/_zm_zonemgr::get_player_zone(); + } +/# + println( "The player is not in a zone at origin " + player.origin ); +#/ + _a1929 = a_spawn_points; + _k1929 = getFirstArrayKey( _a1929 ); + while ( isDefined( _k1929 ) ) + { + spawn_point = _a1929[ _k1929 ]; + while ( spawn_point.script_noteworthy == str_player_zone ) + { + a_spawn_structs = getstructarray( spawn_point.target, "targetname" ); + a_spawn_structs = get_array_of_closest( player.origin, a_spawn_structs ); + _a1939 = a_spawn_structs; + _k1939 = getFirstArrayKey( _a1939 ); + while ( isDefined( _k1939 ) ) + { + s_spawn = _a1939[ _k1939 ]; + if ( !flag( "afterlife_start_over" ) ) + { + if ( isDefined( s_spawn.en_num ) && s_spawn.en_num != player.playernum ) + { + } + } + else + { + if ( positionwouldtelefrag( s_spawn.origin ) || distancesquared( player.origin, s_spawn.origin ) < 250000 ) + { + break; + } + else return s_spawn; + } + _k1939 = getNextArrayKey( _a1939, _k1939 ); + } + a_spawn_structs = get_array_of_farthest( player.origin, a_spawn_structs, undefined, 250000 ); + _a1962 = a_spawn_structs; + _k1962 = getFirstArrayKey( _a1962 ); + while ( isDefined( _k1962 ) ) + { + s_spawn = _a1962[ _k1962 ]; + if ( positionwouldtelefrag( s_spawn.origin ) ) + { + } + else return s_spawn; + _k1962 = getNextArrayKey( _a1962, _k1962 ); + } + } + _k1929 = getNextArrayKey( _a1929, _k1929 ); + } + return undefined; +} + +afterlife_save_perks( ent ) +{ + perk_array = ent get_perk_array( 1 ); + _a1989 = perk_array; + _k1989 = getFirstArrayKey( _a1989 ); + while ( isDefined( _k1989 ) ) + { + perk = _a1989[ _k1989 ]; + ent unsetperk( perk ); + _k1989 = getNextArrayKey( _a1989, _k1989 ); + } + return perk_array; +} + +afterlife_hostmigration() +{ + while ( 1 ) + { + level waittill( "host_migration_end" ); + _a2007 = getplayers(); + _k2007 = getFirstArrayKey( _a2007 ); + while ( isDefined( _k2007 ) ) + { + player = _a2007[ _k2007 ]; + player setclientfieldtoplayer( "player_lives", player.lives ); + if ( isDefined( player.e_afterlife_corpse ) ) + { + player.e_afterlife_corpse setclientfield( "player_corpse_id", 0 ); + } + _k2007 = getNextArrayKey( _a2007, _k2007 ); + } + wait_network_frame(); + wait_network_frame(); + _a2021 = getplayers(); + _k2021 = getFirstArrayKey( _a2021 ); + while ( isDefined( _k2021 ) ) + { + player = _a2021[ _k2021 ]; + if ( isDefined( player.e_afterlife_corpse ) ) + { + player.e_afterlife_corpse setclientfield( "player_corpse_id", player getentitynumber() + 1 ); + } + _k2021 = getNextArrayKey( _a2021, _k2021 ); + } + } +} + +afterlife_reduce_mana( n_mana ) +{ + if ( isDefined( self.afterlife ) && !self.afterlife ) + { + return; + } + if ( isDefined( level.hostmigrationtimer ) ) + { + return; + } + if ( isDefined( self.infinite_mana ) && self.infinite_mana ) + { + self.manacur = 200; + return; + } +/# + if ( getDvarInt( "zombie_cheat" ) >= 1 ) + { + self.manacur = 200; + return; +#/ + } + if ( isDefined( self.e_afterlife_corpse ) && isDefined( self.e_afterlife_corpse.revivetrigger.beingrevived ) && self.e_afterlife_corpse.revivetrigger.beingrevived ) + { + return; + } + self.manacur -= n_mana; +} + +afterlife_lightning_watch( corpse ) +{ + self endon( "disconnect" ); + corpse endon( "player_revived" ); + while ( 1 ) + { + self waittill( "weapon_fired" ); + self afterlife_reduce_mana( 1 ); + wait 0,05; + } +} + +afterlife_jump_watch( corpse ) +{ + self endon( "disconnect" ); + corpse endon( "player_revived" ); + while ( 1 ) + { + if ( self is_jumping() ) + { + self afterlife_reduce_mana( 0,3 ); + earthquake( 0,1, 0,05, self.origin, 200, self ); + } + wait 0,05; + } +} + +afterlife_trigger_create( s_origin ) +{ + s_origin.unitrigger_stub = spawnstruct(); + s_origin.unitrigger_stub.origin = s_origin.origin; + s_origin.unitrigger_stub.radius = 36; + s_origin.unitrigger_stub.height = 256; + s_origin.unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + s_origin.unitrigger_stub.hint_string = &"ZM_PRISON_AFTERLIFE_KILL"; + s_origin.unitrigger_stub.cursor_hint = "HINT_NOICON"; + s_origin.unitrigger_stub.require_look_at = 1; + s_origin.unitrigger_stub.prompt_and_visibility_func = ::afterlife_trigger_visibility; + maps/mp/zombies/_zm_unitrigger::unitrigger_force_per_player_triggers( s_origin.unitrigger_stub, 1 ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( s_origin.unitrigger_stub, ::afterlife_trigger_think ); +} + +reset_all_afterlife_unitriggers() +{ + a_afterlife_triggers = getstructarray( "afterlife_trigger", "targetname" ); + _a2129 = a_afterlife_triggers; + _k2129 = getFirstArrayKey( _a2129 ); + while ( isDefined( _k2129 ) ) + { + struct = _a2129[ _k2129 ]; + maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( struct.unitrigger_stub ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( struct.unitrigger_stub, ::afterlife_trigger_think ); + _k2129 = getNextArrayKey( _a2129, _k2129 ); + } +} + +afterlife_trigger_visibility( player ) +{ + b_is_invis = player.afterlife; + self setinvisibletoplayer( player, b_is_invis ); + if ( player.lives == 0 ) + { + self sethintstring( &"ZM_PRISON_OUT_OF_LIVES" ); + } + else + { + self sethintstring( self.stub.hint_string ); + if ( !isDefined( player.has_played_afterlife_trigger_hint ) && player is_player_looking_at( self.stub.origin, 0,25 ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "killswitch_clue" ); + player.has_played_afterlife_trigger_hint = 1; + } + } + } + return !b_is_invis; +} + +afterlife_trigger_think() +{ + self endon( "kill_trigger" ); + flag_wait( "start_zombie_round_logic" ); + while ( 1 ) + { + self waittill( "trigger", player ); + while ( player.lives <= 0 ) + { + self playsound( "zmb_no_cha_ching" ); + } + while ( player is_reviving_any() || player player_is_in_laststand() ) + { + wait 0,1; + } + if ( isDefined( player.afterlife ) && !player.afterlife ) + { + self setinvisibletoplayer( player, 1 ); + self playsound( "zmb_afterlife_trigger_activate" ); + player playsoundtoplayer( "zmb_afterlife_trigger_electrocute", player ); + player thread afterlife_trigger_used_vo(); + self sethintstring( "" ); + player.keep_perks = 1; + player afterlife_remove(); + player.afterlife = 1; + player thread afterlife_laststand(); + e_fx = spawn( "script_model", self.origin ); + e_fx setmodel( "tag_origin" ); + e_fx.angles = vectorScale( ( 0, 0, 1 ), 90 ); + playfxontag( level._effect[ "afterlife_kill_point_fx" ], e_fx, "tag_origin" ); + wait 2; + e_fx delete(); + self sethintstring( &"ZM_PRISON_AFTERLIFE_KILL" ); + } + } +} + +afterlife_interact_object_think() +{ + self endon( "afterlife_interact_complete" ); + if ( isDefined( self.script_int ) && self.script_int > 0 ) + { + n_total_interact_count = self.script_int; + } + else + { + if ( !isDefined( self.script_int ) || isDefined( self.script_int ) && self.script_int <= 0 ) + { + n_total_interact_count = 0; + } + } + n_count = 0; + self.health = 5000; + self setcandamage( 1 ); + self useanimtree( -1 ); + self playloopsound( "zmb_afterlife_shockbox_off", 1 ); + if ( !isDefined( level.shockbox_anim ) ) + { + level.shockbox_anim[ "on" ] = %fxanim_zom_al_shock_box_on_anim; + level.shockbox_anim[ "off" ] = %fxanim_zom_al_shock_box_off_anim; + } + trig_spawn_offset = ( 0, 0, 1 ); + if ( self.model != "p6_anim_zm_al_nixie_tubes" ) + { + if ( isDefined( self.script_string ) && self.script_string == "intro_powerup_activate" ) + { + self.t_bump = spawn( "trigger_radius", self.origin + vectorScale( ( 0, 0, 1 ), 28 ), 0, 28, 64 ); + } + else + { + if ( issubstr( self.model, "p6_zm_al_shock_box" ) ) + { + trig_spawn_offset = ( 0, 11, 46 ); + str_hint = &"ZM_PRISON_AFTERLIFE_INTERACT"; + } + else + { + if ( issubstr( self.model, "p6_zm_al_power_station_panels" ) ) + { + trig_spawn_offset = ( 32, 35, 58 ); + str_hint = &"ZM_PRISON_AFTERLIFE_OVERLOAD"; + } + } + afterlife_interact_hint_trigger_create( self, trig_spawn_offset, str_hint ); + } + } + while ( 1 ) + { + if ( isDefined( self.unitrigger_stub ) ) + { + self.unitrigger_stub.is_activated_in_afterlife = 0; + } + else + { + if ( isDefined( self.t_bump ) ) + { + self.t_bump setcursorhint( "HINT_NOICON" ); + self.t_bump sethintstring( &"ZM_PRISON_AFTERLIFE_INTERACT" ); + } + } + self waittill( "damage", amount, attacker ); + if ( attacker == level || isplayer( attacker ) && attacker getcurrentweapon() == "lightning_hands_zm" ) + { + if ( isDefined( self.script_string ) ) + { + if ( isDefined( level.afterlife_interact_dist ) ) + { + if ( attacker == level || distancesquared( attacker.origin, self.origin ) < ( level.afterlife_interact_dist * level.afterlife_interact_dist ) ) + { + level notify( self.script_string ); + if ( isDefined( self.unitrigger_stub ) ) + { + self.unitrigger_stub.is_activated_in_afterlife = 1; + self.unitrigger_stub maps/mp/zombies/_zm_unitrigger::run_visibility_function_for_all_triggers(); + } + else + { + if ( isDefined( self.t_bump ) ) + { + self.t_bump sethintstring( "" ); + } + } + self playloopsound( "zmb_afterlife_shockbox_on", 1 ); + if ( self.model == "p6_zm_al_shock_box_off" ) + { + if ( !isDefined( self.playing_fx ) ) + { + playfxontag( level._effect[ "box_activated" ], self, "tag_origin" ); + self.playing_fx = 1; + self thread afterlife_interact_object_fx_cooldown(); + self playsound( "zmb_powerpanel_activate" ); + } + self setmodel( "p6_zm_al_shock_box_on" ); + self setanim( level.shockbox_anim[ "on" ] ); + } + n_count++; + if ( n_total_interact_count <= 0 || n_count < n_total_interact_count ) + { + self waittill( "afterlife_interact_reset" ); + self playloopsound( "zmb_afterlife_shockbox_off", 1 ); + if ( self.model == "p6_zm_al_shock_box_on" ) + { + self setmodel( "p6_zm_al_shock_box_off" ); + self setanim( level.shockbox_anim[ "off" ] ); + } + if ( isDefined( self.unitrigger_stub ) ) + { + self.unitrigger_stub.is_activated_in_afterlife = 0; + self.unitrigger_stub maps/mp/zombies/_zm_unitrigger::run_visibility_function_for_all_triggers(); + } + break; + } + else + { + if ( isDefined( self.t_bump ) ) + { + self.t_bump delete(); + } + return; + } + } + } + } + } + else + { + } + } +} + +afterlife_interact_hint_trigger_create( m_interact, v_trig_offset, str_hint ) +{ + m_interact.unitrigger_stub = spawnstruct(); + m_interact.unitrigger_stub.origin = ( ( m_interact.origin + ( anglesToForward( m_interact.angles ) * v_trig_offset[ 0 ] ) ) + ( anglesToRight( m_interact.angles ) * v_trig_offset[ 1 ] ) ) + ( anglesToUp( m_interact.angles ) * v_trig_offset[ 2 ] ); + m_interact.unitrigger_stub.radius = 40; + m_interact.unitrigger_stub.height = 64; + m_interact.unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + m_interact.unitrigger_stub.hint_string = str_hint; + m_interact.unitrigger_stub.cursor_hint = "HINT_NOICON"; + m_interact.unitrigger_stub.require_look_at = 1; + m_interact.unitrigger_stub.ignore_player_valid = 1; + m_interact.unitrigger_stub.prompt_and_visibility_func = ::afterlife_trigger_visible_in_afterlife; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( m_interact.unitrigger_stub, ::afterlife_interact_hint_trigger_think ); +} + +afterlife_trigger_visible_in_afterlife( player ) +{ + if ( isDefined( self.stub.is_activated_in_afterlife ) ) + { + b_is_invis = self.stub.is_activated_in_afterlife; + } + self setinvisibletoplayer( player, b_is_invis ); + self sethintstring( self.stub.hint_string ); + if ( !b_is_invis ) + { + if ( player is_player_looking_at( self.origin, 0,25 ) ) + { + if ( cointoss() ) + { + player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "need_electricity" ); + } + else + { + player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "electric_zap" ); + } + } + } + return !b_is_invis; +} + +afterlife_interact_hint_trigger_think() +{ + self endon( "kill_trigger" ); + while ( 1 ) + { + self waittill( "trigger" ); + wait 1000; + } +} + +afterlife_interact_object_fx_cooldown() +{ + wait 2; + self.playing_fx = undefined; +} + +afterlife_zombie_damage() +{ + self.actor_damage_func = ::afterlife_damage_func; +} + +afterlife_damage_func( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime ) +{ + if ( sweapon == "lightning_hands_zm" ) + { + while ( !isDefined( self.zapped ) ) + { + a_zombies = get_array_of_closest( self.origin, getaiarray( "axis" ), undefined, 5, 80 ); + i = 0; + while ( i < a_zombies.size ) + { + if ( isalive( a_zombies[ i ] ) && !isDefined( a_zombies[ i ].zapped ) ) + { + a_zombies[ i ] notify( "zapped" ); + a_zombies[ i ] thread [[ level.afterlife_zapped ]](); + wait 0,05; + } + i++; + } + } + return 0; + } + return idamage; +} + +afterlife_zapped() +{ + self endon( "death" ); + self endon( "zapped" ); + if ( self.ai_state == "find_flesh" ) + { + self.zapped = 1; + n_ideal_dist_sq = 490000; + n_min_dist_sq = 10000; + a_nodes = getanynodearray( self.origin, 1200 ); + a_nodes = arraycombine( a_nodes, getanynodearray( self.origin + vectorScale( ( 0, 0, 1 ), 120 ), 1200 ), 0, 0 ); + a_nodes = arraycombine( a_nodes, getanynodearray( self.origin - vectorScale( ( 0, 0, 1 ), 120 ), 1200 ), 0, 0 ); + a_nodes = array_randomize( a_nodes ); + nd_target = undefined; + i = 0; + while ( i < a_nodes.size ) + { + if ( distance2dsquared( a_nodes[ i ].origin, self.origin ) > n_ideal_dist_sq ) + { + if ( a_nodes[ i ] is_valid_teleport_node() ) + { + nd_target = a_nodes[ i ]; + break; + } + } + else + { + i++; + } + } + while ( !isDefined( nd_target ) ) + { + i = 0; + while ( i < a_nodes.size ) + { + if ( distance2dsquared( a_nodes[ i ].origin, self.origin ) > n_min_dist_sq ) + { + if ( a_nodes[ i ] is_valid_teleport_node() ) + { + nd_target = a_nodes[ i ]; + break; + } + } + else + { + i++; + } + } + } + if ( isDefined( nd_target ) ) + { + v_fx_offset = vectorScale( ( 0, 0, 1 ), 40 ); + playfx( level._effect[ "afterlife_teleport" ], self.origin ); + playsoundatposition( "zmb_afterlife_zombie_warp_out", self.origin ); + self hide(); + linker = spawn( "script_model", self.origin + v_fx_offset ); + linker setmodel( "tag_origin" ); + playfxontag( level._effect[ "teleport_ball" ], linker, "tag_origin" ); + linker thread linker_delete_watch( self ); + self linkto( linker ); + linker moveto( nd_target.origin + v_fx_offset, 1 ); + linker waittill( "movedone" ); + linker delete(); + playfx( level._effect[ "afterlife_teleport" ], self.origin ); + playsoundatposition( "zmb_afterlife_zombie_warp_in", self.origin ); + self show(); + } + else + { +/# + iprintln( "Could not teleport" ); +#/ + playfx( level._effect[ "afterlife_teleport" ], self.origin ); + playsoundatposition( "zmb_afterlife_zombie_warp_out", self.origin ); + level.zombie_total++; + self delete(); + return; + } + self.zapped = undefined; + self.ignoreall = 1; + self notify( "stop_find_flesh" ); + self thread afterlife_zapped_fx(); + i = 0; + while ( i < 3 ) + { + self animscripted( self.origin, self.angles, "zm_afterlife_stun" ); + self maps/mp/animscripts/shared::donotetracks( "stunned" ); + i++; + } + self.ignoreall = 0; + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + } +} + +is_valid_teleport_node() +{ + if ( !check_point_in_enabled_zone( self.origin ) ) + { + return 0; + } + if ( self.type != "Path" ) + { + return 0; + } + if ( isDefined( self.script_noteworthy ) && self.script_noteworthy == "no_teleport" ) + { + return 0; + } + if ( isDefined( self.no_teleport ) && self.no_teleport ) + { + return 0; + } + return 1; +} + +linker_delete_watch( ai_zombie ) +{ + self endon( "death" ); + ai_zombie waittill( "death" ); + self delete(); +} + +afterlife_zapped_fx() +{ + self endon( "death" ); + playfxontag( level._effect[ "elec_torso" ], self, "J_SpineLower" ); + self playsound( "zmb_elec_jib_zombie" ); + wait 1; + tagarray = []; + tagarray[ 0 ] = "J_Elbow_LE"; + tagarray[ 1 ] = "J_Elbow_RI"; + tagarray[ 2 ] = "J_Knee_RI"; + tagarray[ 3 ] = "J_Knee_LE"; + tagarray = array_randomize( tagarray ); + playfxontag( level._effect[ "elec_md" ], self, tagarray[ 0 ] ); + self playsound( "zmb_elec_jib_zombie" ); + wait 1; + self playsound( "zmb_elec_jib_zombie" ); + tagarray[ 0 ] = "J_Wrist_RI"; + tagarray[ 1 ] = "J_Wrist_LE"; + if ( !isDefined( self.a.gib_ref ) || self.a.gib_ref != "no_legs" ) + { + tagarray[ 2 ] = "J_Ankle_RI"; + tagarray[ 3 ] = "J_Ankle_LE"; + } + tagarray = array_randomize( tagarray ); + playfxontag( level._effect[ "elec_sm" ], self, tagarray[ 0 ] ); + playfxontag( level._effect[ "elec_sm" ], self, tagarray[ 1 ] ); +} + +enable_afterlife_prop() +{ + self show(); + self.script_noteworthy = "afterlife_prop"; + a_players = getplayers(); + _a2655 = a_players; + _k2655 = getFirstArrayKey( _a2655 ); + while ( isDefined( _k2655 ) ) + { + player = _a2655[ _k2655 ]; + if ( isDefined( player.afterlife ) && player.afterlife ) + { + self setvisibletoplayer( player ); + } + else + { + self setinvisibletoplayer( player ); + } + _k2655 = getNextArrayKey( _a2655, _k2655 ); + } +} + +disable_afterlife_prop() +{ + self.script_noteworthy = undefined; + self setvisibletoall(); +} + +last_stand_conscience_vo() +{ + self endon( "player_revived" ); + self endon( "player_suicide" ); + self endon( "zombified" ); + self endon( "disconnect" ); + self endon( "end_game" ); + if ( !isDefined( self.conscience_vo_played ) ) + { + self.conscience_vo_played = 0; + } + self.conscience_vo_played++; + convo = []; + convo = level.conscience_vo[ "conscience_" + self.character_name + "_convo_" + self.conscience_vo_played ]; + while ( isDefined( convo ) ) + { + wait 5; + a_players = getplayers(); + while ( a_players.size > 1 ) + { + _a2708 = a_players; + _k2708 = getFirstArrayKey( _a2708 ); + while ( isDefined( _k2708 ) ) + { + player = _a2708[ _k2708 ]; + if ( player != self ) + { + if ( distancesquared( self.origin, player.origin ) < 1000000 ) + { + return; + } + } + _k2708 = getNextArrayKey( _a2708, _k2708 ); + } + } + self.dontspeak = 1; + i = 0; + while ( i < convo.size ) + { + n_duration = soundgetplaybacktime( convo[ i ] ); + self playsoundtoplayer( convo[ i ], self ); + self thread conscience_vo_ended_early( convo[ i ] ); + wait ( n_duration / 1000 ); + wait 0,5; + i++; + } + } + self.dontspeak = 0; +} + +conscience_vo_ended_early( str_alias ) +{ + self notify( "conscience_VO_end_early" ); + self endon( "conscience_VO_end_early" ); + self waittill_any( "player_revived", "player_suicide", "zombified", "death", "end_game" ); + self.dontspeak = 0; + self stoplocalsound( str_alias ); +} + +afterlife_trigger_used_vo() +{ + a_vo = level.exert_sounds[ self.characterindex + 1 ][ "hitlrg" ]; + n_index = randomint( a_vo.size ); + self playsound( a_vo[ n_index ] ); +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_ai_brutus.gsc b/zm_prison_patch/maps/mp/zombies/_zm_ai_brutus.gsc new file mode 100644 index 0000000..9e61c1c --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_ai_brutus.gsc @@ -0,0 +1,2939 @@ +#include maps/mp/zm_alcatraz_sq; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_perks; +#include maps/mp/animscripts/zm_death; +#include maps/mp/zombies/_zm_weap_riotshield_prison; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/zm_alcatraz_utility; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_ai_brutus; +#include maps/mp/animscripts/zm_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; +#include maps/mp/zombies/_zm_magicbox; + +precache() +{ + level._effect[ "brutus_flashlight" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_brut_light" ); + level._effect[ "brutus_spawn" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_brut_spawn" ); + level._effect[ "brutus_death" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_brut_spawn" ); + level._effect[ "brutus_teargas" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_brut_gas" ); + level._effect[ "brutus_lockdown" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_perk_lock" ); + level._effect[ "brutus_lockdown_sm" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_perk_s_lock" ); + level._effect[ "brutus_lockdown_lg" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_w_bench_lock" ); + precachemodel( "c_zom_cellbreaker_helmet" ); + precacheshellshock( "mp_radiation_high" ); + precacheshellshock( "mp_radiation_med" ); + precacheshellshock( "mp_radiation_low" ); + precachestring( &"ZOMBIE_LOCKED_COST" ); + precachestring( &"ZOMBIE_LOCKED_COST_2000" ); + precachestring( &"ZOMBIE_LOCKED_COST_4000" ); + precachestring( &"ZOMBIE_LOCKED_COST_6000" ); + flag_init( "brutus_setup_complete" ); + setdvar( "zombie_double_wide_checks", 1 ); + if ( !isDefined( level.vsmgr_prio_zm_brutus_teargas ) ) + { + level.vsmgr_prio_overlay_zm_ai_screecher_blur = 50; + } + if ( !isDefined( level.custom_brutus_barrier_fx ) ) + { + level.custom_brutus_barrier_fx = ::precache_default_brutus_barrier_fx; + } + [[ level.custom_brutus_barrier_fx ]](); +} + +init() +{ + level.brutus_spawners = getentarray( "brutus_zombie_spawner", "script_noteworthy" ); + if ( level.brutus_spawners.size == 0 ) + { + return; + } + array_thread( level.brutus_spawners, ::add_spawn_function, ::brutus_prespawn ); + i = 0; + while ( i < level.brutus_spawners.size ) + { + level.brutus_spawners[ i ].is_enabled = 1; + level.brutus_spawners[ i ].script_forcespawn = 1; + i++; + } + level.brutus_spawn_positions = getstructarray( "brutus_location", "script_noteworthy" ); + level thread setup_interaction_matrix(); + level.sndbrutusistalking = 0; + level.brutus_health = 500; + level.brutus_health_increase = 1000; + level.brutus_round_count = 0; + level.brutus_last_spawn_round = 0; + level.brutus_count = 0; + level.brutus_max_count = 1; + level.brutus_damage_percent = 0,1; + level.brutus_helmet_shots = 5; + level.brutus_team_points_for_death = 500; + level.brutus_player_points_for_death = 250; + level.brutus_points_for_helmet = 250; + level.brutus_alarm_chance = 100; + level.brutus_min_alarm_chance = 100; + level.brutus_alarm_chance_increment = 10; + level.brutus_max_alarm_chance = 200; + level.brutus_min_round_fq = 4; + level.brutus_max_round_fq = 7; + level.brutus_reset_dist_sq = 262144; + level.brutus_aggro_dist_sq = 16384; + level.brutus_aggro_earlyout = 12; + level.brutus_blocker_pieces_req = 1; + level.brutus_zombie_per_round = 1; + level.brutus_players_in_zone_spawn_point_cap = 120; + level.brutus_teargas_duration = 7; + level.player_teargas_duration = 2; + level.brutus_teargas_radius = 64; + level.num_pulls_since_brutus_spawn = 0; + level.brutus_min_pulls_between_box_spawns = 4; + level.brutus_explosive_damage_for_helmet_pop = 1500; + level.brutus_explosive_damage_increase = 600; + level.brutus_failed_paths_to_teleport = 4; + level.brutus_do_prologue = 1; + level.brutus_min_spawn_delay = 10; + level.brutus_max_spawn_delay = 60; + level.brutus_respawn_after_despawn = 1; + level.brutus_in_grief = 0; + if ( getDvar( "ui_gametype" ) == "zgrief" ) + { + level.brutus_in_grief = 1; + } + level.brutus_shotgun_damage_mod = 1,5; + level.brutus_custom_goalradius = 48; + registerclientfield( "actor", "helmet_off", 9000, 1, "int" ); + registerclientfield( "actor", "brutus_lock_down", 9000, 1, "int" ); + level thread maps/mp/zombies/_zm_ai_brutus::brutus_spawning_logic(); + if ( !level.brutus_in_grief ) + { + level thread maps/mp/zombies/_zm_ai_brutus::get_brutus_interest_points(); +/# + setup_devgui(); +#/ + level.custom_perk_validation = ::check_perk_machine_valid; + level.custom_craftable_validation = ::check_craftable_table_valid; + level.custom_plane_validation = ::check_plane_valid; + } +} + +setup_interaction_matrix() +{ + level.interaction_types = []; + level.interaction_types[ "magic_box" ] = spawnstruct(); + level.interaction_types[ "magic_box" ].priority = 0; + level.interaction_types[ "magic_box" ].animstate = "zm_lock_magicbox"; + level.interaction_types[ "magic_box" ].notify_name = "box_lock_anim"; + level.interaction_types[ "magic_box" ].action_notetrack = "locked"; + level.interaction_types[ "magic_box" ].end_notetrack = "lock_done"; + level.interaction_types[ "magic_box" ].validity_func = ::is_magic_box_valid; + level.interaction_types[ "magic_box" ].get_func = ::get_magic_boxes; + level.interaction_types[ "magic_box" ].value_func = ::get_dist_score; + level.interaction_types[ "magic_box" ].interact_func = ::magic_box_lock; + level.interaction_types[ "magic_box" ].spawn_bias = 1000; + level.interaction_types[ "magic_box" ].num_times_to_scale = 1; + level.interaction_types[ "magic_box" ].unlock_cost = 2000; + level.interaction_types[ "perk_machine" ] = spawnstruct(); + level.interaction_types[ "perk_machine" ].priority = 1; + level.interaction_types[ "perk_machine" ].animstate = "zm_lock_perk_machine"; + level.interaction_types[ "perk_machine" ].notify_name = "perk_lock_anim"; + level.interaction_types[ "perk_machine" ].action_notetrack = "locked"; + level.interaction_types[ "perk_machine" ].validity_func = ::is_perk_machine_valid; + level.interaction_types[ "perk_machine" ].get_func = ::get_perk_machines; + level.interaction_types[ "perk_machine" ].value_func = ::get_dist_score; + level.interaction_types[ "perk_machine" ].interact_func = ::perk_machine_lock; + level.interaction_types[ "perk_machine" ].spawn_bias = 800; + level.interaction_types[ "perk_machine" ].num_times_to_scale = 3; + level.interaction_types[ "perk_machine" ].unlock_cost = 2000; + level.interaction_types[ "craftable_table" ] = spawnstruct(); + level.interaction_types[ "craftable_table" ].priority = 2; + level.interaction_types[ "craftable_table" ].animstate = "zm_smash_craftable_table"; + level.interaction_types[ "craftable_table" ].notify_name = "table_smash_anim"; + level.interaction_types[ "craftable_table" ].action_notetrack = "fire"; + level.interaction_types[ "craftable_table" ].validity_func = ::is_craftable_table_valid; + level.interaction_types[ "craftable_table" ].get_func = ::get_craftable_tables; + level.interaction_types[ "craftable_table" ].value_func = ::get_dist_score; + level.interaction_types[ "craftable_table" ].interact_func = ::craftable_table_lock; + level.interaction_types[ "craftable_table" ].spawn_bias = 600; + level.interaction_types[ "craftable_table" ].num_times_to_scale = 1; + level.interaction_types[ "craftable_table" ].unlock_cost = 2000; + level.interaction_types[ "craftable_table" ].interaction_z_offset = -15; + level.interaction_types[ "craftable_table" ].interaction_yaw_offset = 270; + level.interaction_types[ "craftable_table" ].fx_z_offset = -44; + level.interaction_types[ "craftable_table" ].fx_yaw_offset = 270; + level.interaction_types[ "trap" ] = spawnstruct(); + level.interaction_types[ "trap" ].priority = 3; + level.interaction_types[ "trap" ].animstate = "zm_smash_trap"; + level.interaction_types[ "trap" ].notify_name = "trap_smash_anim"; + level.interaction_types[ "trap" ].action_notetrack = "fire"; + level.interaction_types[ "trap" ].validity_func = ::is_trap_valid; + level.interaction_types[ "trap" ].get_func = ::get_traps; + level.interaction_types[ "trap" ].value_func = ::get_dist_score; + level.interaction_types[ "trap" ].interact_func = ::trap_smash; + level.interaction_types[ "trap" ].spawn_bias = 400; + level.interaction_types[ "trap" ].interaction_z_offset = -15; + level.interaction_types[ "plane_ramp" ] = spawnstruct(); + level.interaction_types[ "plane_ramp" ].priority = 4; + level.interaction_types[ "plane_ramp" ].animstate = "zm_lock_plane_ramp"; + level.interaction_types[ "plane_ramp" ].notify_name = "plane_lock_anim"; + level.interaction_types[ "plane_ramp" ].action_notetrack = "locked"; + level.interaction_types[ "plane_ramp" ].end_notetrack = "lock_done"; + level.interaction_types[ "plane_ramp" ].validity_func = ::is_plane_ramp_valid; + level.interaction_types[ "plane_ramp" ].get_func = ::get_plane_ramps; + level.interaction_types[ "plane_ramp" ].value_func = ::get_dist_score; + level.interaction_types[ "plane_ramp" ].interact_func = ::plane_ramp_lock; + level.interaction_types[ "plane_ramp" ].spawn_bias = 500; + level.interaction_types[ "plane_ramp" ].num_times_to_scale = 3; + level.interaction_types[ "plane_ramp" ].unlock_cost = 2000; + level.interaction_types[ "plane_ramp" ].interaction_z_offset = -60; + level.interaction_types[ "plane_ramp" ].fx_z_offset = -60; + level.interaction_types[ "plane_ramp" ].fx_x_offset = 70; + level.interaction_types[ "plane_ramp" ].fx_yaw_offset = 90; + level.interaction_types[ "blocker" ] = spawnstruct(); + level.interaction_types[ "blocker" ].priority = 5; + level.interaction_types[ "blocker" ].animstate = "zm_smash_blocker"; + level.interaction_types[ "blocker" ].notify_name = "board_smash_anim"; + level.interaction_types[ "blocker" ].action_notetrack = "fire"; + level.interaction_types[ "blocker" ].validity_func = ::is_blocker_valid; + level.interaction_types[ "blocker" ].get_func = ::get_blockers; + level.interaction_types[ "blocker" ].value_func = ::get_dist_score; + level.interaction_types[ "blocker" ].interact_func = ::blocker_smash; + level.interaction_types[ "blocker" ].spawn_bias = 50; + level.interaction_priority = []; + interaction_types = getarraykeys( level.interaction_types ); + i = 0; + while ( i < interaction_types.size ) + { + int_type = interaction_types[ i ]; + interaction = level.interaction_types[ int_type ]; +/# + assert( !isDefined( level.interaction_priority[ interaction.priority ] ) ); +#/ + level.interaction_priority[ interaction.priority ] = int_type; + i++; + } +/# + i = 0; + while ( i < interaction_types.size ) + { + assert( isDefined( level.interaction_priority[ i ] ) ); + i++; +#/ + } +} + +brutus_prespawn() +{ +} + +brutus_spawn_prologue( spawn_pos ) +{ + playsoundatposition( "zmb_ai_brutus_prespawn", spawn_pos.origin ); + wait 3; +} + +brutus_spawn( starting_health, has_helmet, helmet_hits, explosive_dmg_taken, zone_name ) +{ + level.num_pulls_since_brutus_spawn = 0; + self set_zombie_run_cycle( "run" ); + if ( !isDefined( has_helmet ) ) + { + self.has_helmet = 1; + } + else + { + self.has_helmet = has_helmet; + } + if ( !isDefined( helmet_hits ) ) + { + self.helmet_hits = 0; + } + else + { + self.helmet_hits = helmet_hits; + } + if ( !isDefined( explosive_dmg_taken ) ) + { + self.explosive_dmg_taken = 0; + } + else + { + self.explosive_dmg_taken = explosive_dmg_taken; + } + if ( !isDefined( starting_health ) ) + { + self brutus_health_increases(); + self.maxhealth = level.brutus_health; + self.health = level.brutus_health; + } + else + { + self.maxhealth = starting_health; + self.health = starting_health; + } + self.explosive_dmg_req = level.brutus_expl_dmg_req; + self.no_damage_points = 1; + self endon( "death" ); + level endon( "intermission" ); + self.animname = "brutus_zombie"; + self.audio_type = "brutus"; + self.has_legs = 1; + self.ignore_all_poi = 1; + self.is_brutus = 1; + self.ignore_enemy_count = 1; + self.instakill_func = ::brutus_instakill_override; + self.nuke_damage_func = ::brutus_nuke_override; + self.melee_anim_func = ::melee_anim_func; + self.meleedamage = 99; + self.custom_item_dmg = 1000; + self.brutus_lockdown_state = 0; + recalc_zombie_array(); + self setphysparams( 20, 0, 60 ); + self.zombie_init_done = 1; + self notify( "zombie_init_done" ); + self.allowpain = 0; + self animmode( "normal" ); + self orientmode( "face enemy" ); + self maps/mp/zombies/_zm_spawner::zombie_setup_attack_properties(); + self setfreecameralockonallowed( 0 ); + level thread maps/mp/zombies/_zm_spawner::zombie_death_event( self ); + self thread maps/mp/zombies/_zm_spawner::enemy_death_detection(); + if ( isDefined( zone_name ) && zone_name == "zone_golden_gate_bridge" ) + { + wait randomfloat( 1,5 ); + spawn_pos = get_random_brutus_spawn_pos( zone_name ); + } + else + { + spawn_pos = get_best_brutus_spawn_pos( zone_name ); + } + if ( !isDefined( spawn_pos ) ) + { +/# + println( "ERROR: Tried to spawn brutus with no brutus spawn_positions!\n" ); + iprintln( "ERROR: Tried to spawn brutus with no brutus spawn_positions!" ); +#/ + self delete(); + return; + } + if ( !isDefined( spawn_pos.angles ) ) + { + spawn_pos.angles = ( 0, 0, 0 ); + } + if ( isDefined( level.brutus_do_prologue ) && level.brutus_do_prologue ) + { + self brutus_spawn_prologue( spawn_pos ); + } + if ( !self.has_helmet ) + { + self detach( "c_zom_cellbreaker_helmet" ); + } + level.brutus_count++; + self maps/mp/zombies/_zm_spawner::zombie_complete_emerging_into_playable_area(); + self thread snddelayedmusic(); + self thread brutus_death(); + self thread brutus_check_zone(); + self thread brutus_watch_enemy(); + self forceteleport( spawn_pos.origin, spawn_pos.angles ); + self.cant_melee = 1; + self.not_interruptable = 1; + self.actor_damage_func = ::brutus_damage_override; + self.non_attacker_func = ::brutus_non_attacker_damage_override; + self thread brutus_lockdown_client_effects( 0,5 ); + playfx( level._effect[ "brutus_spawn" ], self.origin ); + playsoundatposition( "zmb_ai_brutus_spawn", self.origin ); + self animscripted( spawn_pos.origin, spawn_pos.angles, "zm_spawn" ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "spawn_anim" ); + self waittillmatch( "spawn_anim" ); + return "spawn_complete"; + self.not_interruptable = 0; + self.cant_melee = 0; + self thread brutus_chest_flashlight(); + self thread brutus_find_flesh(); + self thread maps/mp/zombies/_zm_spawner::delayed_zombie_eye_glow(); + level notify( "brutus_spawned" ); +} + +brutus_chest_flashlight() +{ + wait 0,1; + self.chest_flashlight = spawn( "script_model", self.origin ); + self.chest_flashlight setmodel( "tag_origin" ); + self.chest_flashlight linkto( self, "J_spineupper", ( 0, 0, 0 ), ( 0, 0, 0 ) ); + playfxontag( level._effect[ "brutus_flashlight" ], self.chest_flashlight, "tag_origin" ); + self waittill( "death" ); + if ( isDefined( self.chest_flashlight ) ) + { + self.chest_flashlight delete(); + } +} + +brutus_temp_despawn( brutus, endon_notify, respawn_notify ) +{ + level endon( endon_notify ); + align_struct = spawn( "script_model", brutus.origin ); + align_struct.angles = brutus.angles; + align_struct setmodel( "tag_origin" ); + if ( !level.brutus_in_grief || brutus istouching( level.e_gondola.t_ride ) && isDefined( brutus.force_gondola_teleport ) && brutus.force_gondola_teleport ) + { + brutus.force_gondola_teleport = 0; + align_struct linkto( level.e_gondola ); + brutus linkto( align_struct ); + } + brutus.not_interruptable = 1; + playfxontag( level._effect[ "brutus_spawn" ], align_struct, "tag_origin" ); + brutus animscripted( brutus.origin, brutus.angles, "zm_taunt" ); + brutus maps/mp/animscripts/zm_shared::donotetracks( "taunt_anim" ); + brutus.not_interruptable = 0; + brutus ghost(); + brutus notify( "brutus_cleanup" ); + brutus notify( "brutus_teleporting" ); + if ( isDefined( align_struct ) ) + { + align_struct delete(); + } + if ( isDefined( brutus.sndbrutusmusicent ) ) + { + brutus.sndbrutusmusicent delete(); + brutus.sndbrutusmusicent = undefined; + } + health = brutus.health; + has_helmet = brutus.has_helmet; + helmet_hits = brutus.helmet_hits; + explosive_dmg_taken = brutus.explosive_dmg_taken; + zone_name = brutus.force_zone; + brutus delete(); + level.brutus_count--; + + level waittill( respawn_notify ); + wait randomfloatrange( 1, 2,5 ); + level thread respawn_brutus( health, has_helmet, helmet_hits, explosive_dmg_taken, zone_name ); +} + +brutus_spawn_zone_locked( zone_name ) +{ + ai = spawn_zombie( level.brutus_spawners[ 0 ] ); + ai thread brutus_spawn( undefined, undefined, undefined, undefined, zone_name ); + ai.force_zone = zone_name; + if ( isDefined( ai ) ) + { + ai playsound( "zmb_ai_brutus_spawn_2d" ); + return ai; + } +} + +brutus_spawn_in_zone( zone_name, zone_locked ) +{ + if ( isDefined( zone_locked ) && zone_locked ) + { + return brutus_spawn_zone_locked( zone_name ); + } + else + { + ai = spawn_zombie( level.brutus_spawners[ 0 ] ); + ai thread brutus_spawn( undefined, undefined, undefined, undefined, zone_name ); + if ( isDefined( ai ) ) + { + ai playsound( "zmb_ai_brutus_spawn_2d" ); + return ai; + } + } +} + +snddelayedmusic() +{ + self endon( "death" ); + wait 5; + if ( !isDefined( self.sndbrutusmusicent ) ) + { + sndentorigin = self gettagorigin( "J_spineupper" ); + self.sndbrutusmusicent = spawn( "script_origin", sndentorigin ); + self.sndbrutusmusicent linkto( self, "J_spineupper" ); + self.sndbrutusmusicent playloopsound( "mus_event_brutus_loop" ); + } + self thread sndbrutusloopwatcher( self.sndbrutusmusicent ); +} + +sndbrutusloopwatcher( ent ) +{ + self endon( "death" ); + level waittill( "sndStopBrutusLoop" ); + ent stoploopsound( 1 ); + wait 1; + ent delete(); +} + +brutus_health_increases() +{ + if ( level.round_number > level.brutus_last_spawn_round ) + { + a_players = getplayers(); + n_player_modifier = 1; + if ( a_players.size > 1 ) + { + n_player_modifier = a_players.size * 0,75; + } + level.brutus_round_count++; + level.brutus_health = int( level.brutus_health_increase * n_player_modifier * level.brutus_round_count ); + level.brutus_expl_dmg_req = int( level.brutus_explosive_damage_increase * n_player_modifier * level.brutus_round_count ); + if ( level.brutus_health >= ( 5000 * n_player_modifier ) ) + { + level.brutus_health = int( 5000 * n_player_modifier ); + } + if ( level.brutus_expl_dmg_req >= ( 4500 * n_player_modifier ) ) + { + level.brutus_expl_dmg_req = int( 4500 * n_player_modifier ); + } + level.brutus_last_spawn_round = level.round_number; + } +} + +get_brutus_spawn_pos_val( brutus_pos ) +{ + score = 0; + zone_name = brutus_pos.zone_name; + if ( !maps/mp/zombies/_zm_zonemgr::zone_is_enabled( zone_name ) ) + { + return 0; + } + a_players_in_zone = get_players_in_zone( zone_name, 1 ); + if ( a_players_in_zone.size == 0 ) + { + return 0; + } + else + { + n_score_addition = 1; + i = 0; + while ( i < a_players_in_zone.size ) + { + if ( findpath( brutus_pos.origin, a_players_in_zone[ i ].origin, self, 0, 0 ) ) + { + n_dist = distance2d( brutus_pos.origin, a_players_in_zone[ i ].origin ); + n_score_addition += linear_map( n_dist, 2000, 0, 0, level.brutus_players_in_zone_spawn_point_cap ); + } + i++; + } + if ( n_score_addition > level.brutus_players_in_zone_spawn_point_cap ) + { + n_score_addition = level.brutus_players_in_zone_spawn_point_cap; + } + score += n_score_addition; + } + while ( !level.brutus_in_grief ) + { + interaction_types = getarraykeys( level.interaction_types ); + interact_array = level.interaction_types; + i = 0; + while ( i < interaction_types.size ) + { + int_type = interaction_types[ i ]; + interaction = interact_array[ int_type ]; + interact_points = [[ interaction.get_func ]]( zone_name ); + j = 0; + while ( j < interact_points.size ) + { + if ( interact_points[ j ] [[ interaction.validity_func ]]() ) + { + score += interaction.spawn_bias; + } + j++; + } + i++; + } + } + return score; +} + +get_random_brutus_spawn_pos( zone_name ) +{ + zone_spawn_pos = []; + i = 0; + while ( i < level.zombie_brutus_locations.size ) + { + if ( isDefined( zone_name ) && level.zombie_brutus_locations[ i ].zone_name != zone_name ) + { + i++; + continue; + } + else + { + zone_spawn_pos[ zone_spawn_pos.size ] = i; + } + i++; + } + if ( zone_spawn_pos.size > 0 ) + { + pos_idx = randomint( zone_spawn_pos.size ); + return level.zombie_brutus_locations[ zone_spawn_pos[ pos_idx ] ]; + } + return undefined; +} + +get_best_brutus_spawn_pos( zone_name ) +{ + val = 0; + i = 0; + while ( i < level.zombie_brutus_locations.size ) + { + if ( isDefined( zone_name ) && level.zombie_brutus_locations[ i ].zone_name != zone_name ) + { + i++; + continue; + } + else + { + newval = get_brutus_spawn_pos_val( level.zombie_brutus_locations[ i ] ); + if ( newval > val ) + { + val = newval; + pos_idx = i; + } + } + i++; + } + if ( isDefined( pos_idx ) ) + { + return level.zombie_brutus_locations[ pos_idx ]; + } + else + { + return undefined; + } +} + +play_ambient_brutus_vocals() +{ + self endon( "death" ); + wait randomintrange( 2, 4 ); + while ( 1 ) + { + if ( isDefined( self ) ) + { + if ( isDefined( self.favoriteenemy ) && distance( self.origin, self.favoriteenemy.origin ) <= 150 ) + { + break; + } + else + { + self playsound( "zmb_vocals_brutus_ambience" ); + } + } + wait randomfloatrange( 1, 1,5 ); + } +} + +brutus_cleanup() +{ + self waittill( "brutus_cleanup" ); + level.sndbrutusistalking = 0; + if ( isDefined( self.sndbrutusmusicent ) ) + { + self.sndbrutusmusicent delete(); + self.sndbrutusmusicent = undefined; + } +} + +brutus_cleanup_at_end_of_grief_round() +{ + self endon( "death" ); + self endon( "brutus_cleanup" ); + level waittill_any( "keep_griefing", "game_module_ended" ); + self delete(); + self notify( "brutus_cleanup" ); +} + +brutus_death() +{ + self endon( "brutus_cleanup" ); + self thread brutus_cleanup(); + if ( level.brutus_in_grief ) + { + self thread brutus_cleanup_at_end_of_grief_round(); + } + self waittill( "death" ); + self thread sndbrutusvox( "vox_brutus_brutus_defeated" ); + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "brutus_death" ); + level.brutus_count--; + + playfx( level._effect[ "brutus_death" ], self.origin ); + playsoundatposition( "zmb_ai_brutus_death", self.origin ); + if ( get_current_zombie_count() == 0 && level.zombie_total == 0 ) + { + level.last_brutus_origin = self.origin; + level notify( "last_brutus_down" ); + if ( isDefined( self.brutus_round_spawn_failsafe ) && self.brutus_round_spawn_failsafe ) + { + level.next_brutus_round = level.round_number + 1; + } + } + else + { + if ( isDefined( self.brutus_round_spawn_failsafe ) && self.brutus_round_spawn_failsafe ) + { + level.zombie_total++; + level.zombie_total_subtract++; + level thread brutus_round_spawn_failsafe_respawn(); + } + } + if ( isDefined( self.suppress_brutus_powerup_drop ) && !self.suppress_brutus_powerup_drop ) + { + if ( isDefined( level.global_brutus_powerup_prevention ) && !level.global_brutus_powerup_prevention ) + { + if ( self maps/mp/zombies/_zm_zonemgr::entity_in_zone( "zone_golden_gate_bridge" ) ) + { + level.global_brutus_powerup_prevention = 1; + } + if ( level.powerup_drop_count >= level.zombie_vars[ "zombie_powerup_drop_max_per_round" ] ) + { + level.powerup_drop_count = level.zombie_vars[ "zombie_powerup_drop_max_per_round" ] - 1; + } + level.zombie_vars[ "zombie_drop_item" ] = 1; + level thread maps/mp/zombies/_zm_powerups::powerup_drop( self.origin ); + } + } + while ( isplayer( self.attacker ) ) + { + event = "death"; + if ( issubstr( self.damageweapon, "knife_ballistic_" ) ) + { + event = "ballistic_knife_death"; + } + self.attacker thread do_player_general_vox( "general", "brutus_killed", 20, 20 ); + if ( level.brutus_in_grief ) + { + team_points = level.brutus_team_points_for_death; + player_points = level.brutus_player_points_for_death; + a_players = getplayers( self.team ); + } + else + { + multiplier = maps/mp/zombies/_zm_score::get_points_multiplier( self ); + team_points = multiplier * round_up_score( level.brutus_team_points_for_death, 5 ); + player_points = multiplier * round_up_score( level.brutus_player_points_for_death, 5 ); + a_players = getplayers(); + } + _a922 = a_players; + _k922 = getFirstArrayKey( _a922 ); + while ( isDefined( _k922 ) ) + { + player = _a922[ _k922 ]; + if ( !is_player_valid( player ) ) + { + } + else + { + player add_to_player_score( team_points ); + if ( player == self.attacker ) + { + player add_to_player_score( player_points ); + level notify( "brutus_killed" ); + } + player.pers[ "score" ] = player.score; + player maps/mp/zombies/_zm_stats::increment_client_stat( "prison_brutus_killed", 0 ); + } + _k922 = getNextArrayKey( _a922, _k922 ); + } + } + self notify( "brutus_cleanup" ); +} + +brutus_round_spawn_failsafe_respawn() +{ + while ( 1 ) + { + wait 2; + if ( attempt_brutus_spawn( 1 ) ) + { + return; + } + else + { + } + } +} + +get_interact_offset( item, target_type ) +{ +/# + assert( isDefined( level.interaction_types[ target_type ] ) ); +#/ + interaction = level.interaction_types[ target_type ]; + anim_state = interaction.animstate; + animationid = self getanimfromasd( anim_state, 0 ); + origin = item.origin; + angles = item.angles; + if ( isDefined( interaction.interaction_z_offset ) ) + { + origin += ( 0, 0, interaction.interaction_z_offset ); + } + if ( isDefined( interaction.interaction_yaw_offset ) ) + { + angles += ( 0, interaction.interaction_yaw_offset, 0 ); + } + return getstartorigin( origin, angles, animationid ); +} + +enable_brutus_rounds() +{ + level.brutus_rounds_enabled = 1; + flag_init( "brutus_round" ); + level thread brutus_round_tracker(); +} + +brutus_round_tracker() +{ + level.next_brutus_round = level.round_number + randomintrange( level.brutus_min_round_fq, level.brutus_max_round_fq ); + old_spawn_func = level.round_spawn_func; + old_wait_func = level.round_wait_func; + for ( ;; ) + { + while ( 1 ) + { + level waittill( "between_round_over" ); + players = get_players(); + if ( level.round_number < 9 && isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game ) + { + } + } + else if ( level.next_brutus_round <= level.round_number ) + { + while ( maps/mp/zm_alcatraz_utility::is_team_on_golden_gate_bridge() ) + { + level.next_brutus_round = level.round_number + 1; + } + wait randomfloatrange( level.brutus_min_spawn_delay, level.brutus_max_spawn_delay ); + if ( attempt_brutus_spawn( level.brutus_zombie_per_round ) ) + { + level.music_round_override = 1; + level thread maps/mp/zombies/_zm_audio::change_zombie_music( "brutus_round_start" ); + level thread sndforcewait(); + level.next_brutus_round = level.round_number + randomintrange( level.brutus_min_round_fq, level.brutus_max_round_fq ); + } + } + } +} + +sndforcewait() +{ + wait 10; + level.music_round_override = 0; +} + +wait_on_box_alarm() +{ + while ( 1 ) + { + self.zbarrier waittill( "randomization_done" ); + level.num_pulls_since_brutus_spawn++; + if ( level.brutus_in_grief ) + { + level.brutus_min_pulls_between_box_spawns = randomintrange( 7, 10 ); + } + if ( level.num_pulls_since_brutus_spawn >= level.brutus_min_pulls_between_box_spawns ) + { + rand = randomint( 1000 ); + if ( level.brutus_in_grief ) + { + level notify( "spawn_brutus" ); + break; + } + else if ( rand <= level.brutus_alarm_chance ) + { + while ( flag( "moving_chest_now" ) ) + { + continue; + } + if ( attempt_brutus_spawn( 1 ) ) + { + if ( level.next_brutus_round == ( level.round_number + 1 ) ) + { + level.next_brutus_round++; + } + level.brutus_alarm_chance = level.brutus_min_alarm_chance; + } + break; + } + else + { + if ( level.brutus_alarm_chance < level.brutus_max_alarm_chance ) + { + level.brutus_alarm_chance += level.brutus_alarm_chance_increment; + } + } + } + } +} + +brutus_spawning_logic() +{ + if ( !level.brutus_in_grief ) + { + level thread enable_brutus_rounds(); + } + while ( isDefined( level.chests ) ) + { + i = 0; + while ( i < level.chests.size ) + { + level.chests[ i ] thread wait_on_box_alarm(); + i++; + } + } + while ( 1 ) + { + level waittill( "spawn_brutus", num ); + i = 0; + while ( i < num ) + { + ai = spawn_zombie( level.brutus_spawners[ 0 ] ); + ai thread brutus_spawn(); + i++; + } + if ( isDefined( ai ) ) + { + ai playsound( "zmb_ai_brutus_spawn_2d" ); + } + } +} + +attempt_brutus_spawn( n_spawn_num ) +{ + if ( ( level.brutus_count + n_spawn_num ) > level.brutus_max_count ) + { +/# + iprintln( "Brutus max count reached - Preventing Brutus from spawning!" ); +#/ + return 0; + } + level notify( "spawn_brutus" ); + return 1; +} + +brutus_start_basic_find_flesh() +{ + self.goalradius = 48; + self.custom_goalradius_override = level.brutus_custom_goalradius; + if ( self.ai_state != "find_flesh" ) + { + self.ai_state = "find_flesh"; + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + } +} + +brutus_stop_basic_find_flesh() +{ + if ( self.ai_state == "find_flesh" ) + { + self notify( "stop_find_flesh" ); + self notify( "zombie_acquire_enemy" ); + } +} + +setup_devgui() +{ +/# + setdvar( "spawn_Brutus", "off" ); + adddebugcommand( "devgui_cmd "Zombies:2/Zombie Spawning:2/Spawn Zombie:1/Brutus:1" "spawn_Brutus on"\n" ); + level thread watch_devgui_brutus(); +#/ +} + +watch_devgui_brutus() +{ +/# + while ( 1 ) + { + if ( getDvar( "spawn_Brutus" ) == "on" ) + { + level notify( "spawn_brutus" ); + setdvar( "spawn_Brutus", "off" ); + } + wait 0,1; +#/ + } +} + +respawn_brutus( starting_health, has_helmet, helmet_hits, explosive_dmg_taken, zone_name, b_no_current_valid_targets ) +{ + if ( isDefined( b_no_current_valid_targets ) && b_no_current_valid_targets ) + { + zone_name = brutus_watch_for_new_valid_targets(); + } + else + { + wait 5; + } + ai = spawn_zombie( level.brutus_spawners[ 0 ] ); + ai thread brutus_spawn( starting_health, has_helmet, helmet_hits, explosive_dmg_taken, zone_name ); + ai.force_zone = zone_name; +} + +respawn_brutus_after_gondola( starting_health, has_helmet, helmet_hits, explosive_dmg_taken ) +{ + level waittill( "gondola_arrived", zone_name ); + ai = spawn_zombie( level.brutus_spawners[ 0 ] ); + ai thread brutus_spawn( starting_health, has_helmet, helmet_hits, explosive_dmg_taken, zone_name ); +} + +brutus_watch_for_gondola() +{ + self endon( "death" ); + while ( 1 ) + { + level waittill( "gondola_moving" ); + if ( !level.brutus_in_grief && self istouching( level.e_gondola.t_ride ) ) + { + self.force_gondola_teleport = 1; + } + wait 0,05; + } +} + +are_all_targets_invalid() +{ + a_players = getplayers(); + _a1238 = a_players; + _k1238 = getFirstArrayKey( _a1238 ); + while ( isDefined( _k1238 ) ) + { + player = _a1238[ _k1238 ]; + if ( isDefined( player.is_on_gondola ) && !player.is_on_gondola && isDefined( player.afterlife ) && !player.afterlife ) + { + return 0; + } + _k1238 = getNextArrayKey( _a1238, _k1238 ); + } + return 1; +} + +brutus_watch_for_new_valid_targets() +{ + level thread brutus_watch_for_gondola_arrive(); + level thread brutus_watch_for_non_afterlife_players(); + level waittill( "brutus_valid_targets_arrived", zone_name ); + return zone_name; +} + +brutus_watch_for_gondola_arrive() +{ + level endon( "brutus_valid_targets_arrived" ); + level waittill( "gondola_arrived", zone_name ); + level notify( "brutus_valid_targets_arrived" ); +} + +brutus_watch_for_non_afterlife_players() +{ + level endon( "brutus_valid_targets_arrived" ); + b_all_players_in_afterlife = 1; + while ( b_all_players_in_afterlife ) + { + a_players = getplayers(); + _a1273 = a_players; + _k1273 = getFirstArrayKey( _a1273 ); + while ( isDefined( _k1273 ) ) + { + player = _a1273[ _k1273 ]; + if ( isDefined( player.afterlife ) && !player.afterlife && !player maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + b_all_players_in_afterlife = 0; + } + _k1273 = getNextArrayKey( _a1273, _k1273 ); + } + wait 0,5; + } + level notify( "brutus_valid_targets_arrived" ); +} + +brutus_stuck_teleport() +{ + self endon( "death" ); + align_struct = spawn( "script_model", self.origin ); + align_struct.angles = self.angles; + align_struct setmodel( "tag_origin" ); + if ( !level.brutus_in_grief || self istouching( level.e_gondola.t_ride ) && isDefined( self.force_gondola_teleport ) && self.force_gondola_teleport ) + { + self.force_gondola_teleport = 0; + align_struct linkto( level.e_gondola ); + self linkto( align_struct ); + } + self.not_interruptable = 1; + playfxontag( level._effect[ "brutus_spawn" ], align_struct, "tag_origin" ); + self animscripted( self.origin, self.angles, "zm_taunt" ); + self maps/mp/animscripts/zm_shared::donotetracks( "taunt_anim" ); + self.not_interruptable = 0; + self ghost(); + self notify( "brutus_cleanup" ); + self notify( "brutus_teleporting" ); + if ( isDefined( align_struct ) ) + { + align_struct delete(); + } + if ( isDefined( self.sndbrutusmusicent ) ) + { + self.sndbrutusmusicent delete(); + self.sndbrutusmusicent = undefined; + } + if ( isDefined( level.brutus_respawn_after_despawn ) && level.brutus_respawn_after_despawn ) + { + b_no_current_valid_targets = are_all_targets_invalid(); + level thread respawn_brutus( self.health, self.has_helmet, self.helmet_hits, self.explosive_dmg_taken, self.force_zone, b_no_current_valid_targets ); + } + level.brutus_count--; + + self delete(); +} + +watch_for_riot_shield_melee() +{ + self endon( "new_stuck_watcher" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "item_attack" ); + self.fail_count = 0; + } +} + +watch_for_valid_melee() +{ + self endon( "new_stuck_watcher" ); + self endon( "death" ); + while ( 1 ) + { + self waittillmatch( "melee_anim" ); + return "end"; + if ( isDefined( self.favorite_enemy ) && distancesquared( self.origin, self.favorite_enemy.origin ) < 16384 && isDefined( self.favorite_enemy.is_on_gondola ) && !self.favorite_enemy.is_on_gondola ) + { + self.fail_count = 0; + } + } +} + +brutus_stuck_watcher() +{ + self notify( "new_stuck_watcher" ); + self endon( "death" ); + self endon( "new_stuck_watcher" ); + self.fail_count = 0; + self thread watch_for_valid_melee(); + self thread watch_for_riot_shield_melee(); + while ( 1 ) + { + while ( !isDefined( self.goal_pos ) ) + { + wait 0,05; + } + while ( self.not_interruptable ) + { + wait 1; + } + if ( !findpath( self.origin, self.goal_pos, self, 0, 0 ) ) + { +/# + println( "Brutus could not path to goal_pos " + self.goal_pos ); +#/ + self.fail_count++; + } + else + { + self.fail_count = 0; + } + if ( self.fail_count >= level.brutus_failed_paths_to_teleport ) + { + self brutus_stuck_teleport(); + return; + } + wait 1; + } +} + +should_brutus_aggro( player_zone, brutus_zone ) +{ + if ( !isDefined( player_zone ) || !isDefined( brutus_zone ) ) + { + return 0; + } + if ( player_zone == brutus_zone ) + { + return 1; + } + if ( isDefined( level.zones[ brutus_zone ].adjacent_zones ) && isDefined( level.zones[ brutus_zone ].adjacent_zones[ player_zone ] ) ) + { + return 1; + } + return 0; +} + +brutus_find_flesh() +{ + self endon( "death" ); + level endon( "intermission" ); + if ( level.intermission ) + { + return; + } + self.ai_state = "idle"; + self.helitarget = 1; + self.ignoreme = 0; + self.nododgemove = 1; + self.ignore_player = []; + self thread brutus_watch_for_gondola(); + self thread brutus_stuck_watcher(); + self thread brutus_goal_watcher(); + self thread watch_for_player_dist(); + while ( 1 ) + { + while ( self.not_interruptable ) + { + wait 0,05; + } + player = brutus_get_closest_valid_player(); + brutus_zone = get_zone_from_position( self.origin ); + while ( !isDefined( brutus_zone ) ) + { + brutus_zone = self.prev_zone; + while ( !isDefined( brutus_zone ) ) + { + wait 1; + } + } + player_zone = undefined; + self.prev_zone = brutus_zone; + if ( level.brutus_in_grief ) + { + brutus_start_basic_find_flesh(); + } + else if ( !isDefined( player ) ) + { + self.priority_item = self get_priority_item_for_brutus( brutus_zone, 1 ); + } + else player_zone = player get_player_zone(); + if ( isDefined( player_zone ) ) + { + self.priority_item = self get_priority_item_for_brutus( player_zone ); + } + else + { + self.priority_item = self get_priority_item_for_brutus( brutus_zone, 1 ); + } + if ( isDefined( player ) && distancesquared( self.origin, player.origin ) < level.brutus_aggro_dist_sq && isDefined( player_zone ) && should_brutus_aggro( player_zone, brutus_zone ) ) + { + self.favorite_enemy = player; + self.goal_pos = player.origin; + brutus_start_basic_find_flesh(); + } + else + { + if ( isDefined( self.priority_item ) ) + { + brutus_stop_basic_find_flesh(); + self.goalradius = 12; + self.custom_goalradius_override = 12; + self.goal_pos = self get_interact_offset( self.priority_item, self.ai_state ); + self setgoalpos( self.goal_pos ); + break; + } + else if ( isDefined( player ) ) + { + self.favorite_enemy = player; + self.goal_pos = self.favorite_enemy.origin; + brutus_start_basic_find_flesh(); + break; + } + else + { + self.goal_pos = self.origin; + self.ai_state = "idle"; + self setanimstatefromasd( "zm_idle" ); + self setgoalpos( self.goal_pos ); + } + } + wait 1; + } +} + +trap_damage_callback( trap ) +{ + self endon( "death" ); + if ( isDefined( self.not_interruptable ) && !self.not_interruptable ) + { + self.not_interruptable = 1; + self animscripted( self.origin, self.angles, "zm_taunt" ); + self maps/mp/animscripts/shared::donotetracks( "taunt_anim" ); + if ( trap.targetname == "fan_trap" ) + { + trap notify( "trap_finished_" + trap.script_string ); + } + else + { + if ( trap.targetname == "acid_trap" ) + { + trap notify( "acid_trap_fx_done" ); + } + } + self.not_interruptable = 0; + } +} + +zone_array_contains( zone_array, zone_name ) +{ + j = 0; + while ( j < zone_array.size ) + { + if ( zone_array[ j ] == zone_name ) + { + return 1; + } + j++; + } + return 0; +} + +get_priority_item_for_brutus( zone_name, do_secondary_zone_checks ) +{ + interact_types = level.interaction_types; + interact_prio = level.interaction_priority; + i = 0; + while ( i < interact_prio.size ) + { + best_score = -1; + best_object = undefined; + int_type = interact_prio[ i ]; + int_struct = interact_types[ int_type ]; + int_objects = self [[ int_struct.get_func ]]( zone_name ); + j = 0; + while ( j < int_objects.size ) + { + if ( int_objects[ j ] [[ int_struct.validity_func ]]() ) + { + score = self [[ int_struct.value_func ]]( int_objects[ j ] ); +/# + assert( score >= 0 ); +#/ + if ( score < best_score || best_score < 0 ) + { + best_object = int_objects[ j ]; + best_score = score; + } + } + j++; + } + if ( isDefined( best_object ) ) + { + self.ai_state = int_type; + return best_object; + } + i++; + } + while ( isDefined( do_secondary_zone_checks ) && do_secondary_zone_checks ) + { + adj_zone_names = getarraykeys( level.zones[ zone_name ].adjacent_zones ); + i = 0; + while ( i < adj_zone_names.size ) + { + if ( !maps/mp/zombies/_zm_zonemgr::zone_is_enabled( adj_zone_names[ i ] ) ) + { + i++; + continue; + } + else + { + best_object = get_priority_item_for_brutus( adj_zone_names[ i ] ); + if ( isDefined( best_object ) ) + { + return best_object; + } + } + i++; + } + global_zone_names = getarraykeys( level.zones ); + i = 0; + while ( i < global_zone_names.size ) + { + if ( global_zone_names[ i ] == zone_name ) + { + i++; + continue; + } + else if ( zone_array_contains( adj_zone_names, global_zone_names[ i ] ) ) + { + i++; + continue; + } + else if ( !maps/mp/zombies/_zm_zonemgr::zone_is_enabled( global_zone_names[ i ] ) ) + { + i++; + continue; + } + else + { + best_object = get_priority_item_for_brutus( global_zone_names[ i ] ); + if ( isDefined( best_object ) ) + { + return best_object; + } + } + i++; + } + } + return undefined; +} + +get_dist_score( object ) +{ + return distancesquared( self.origin, object.origin ); +} + +get_trap_score( object ) +{ + if ( sighttracepassed( self.origin + ( 0, 0, 0 ), object.origin, 0, self ) ) + { + return 0; + } + return distancesquared( self.origin, object.origin ); +} + +get_magic_boxes( zone_name ) +{ +/# + assert( isDefined( level.zones[ zone_name ] ) ); +#/ + return level.zones[ zone_name ].magic_boxes; +} + +is_magic_box_valid() +{ + if ( self is_chest_active() && self == level.chests[ level.chest_index ] ) + { + return 1; + } + return 0; +} + +get_perk_machine_trigger() +{ + if ( self.targetname == "vendingelectric_cherry" ) + { + perk_machine = getent( "vending_electriccherry", "target" ); + } + else if ( self.targetname == "vending_deadshot_model" ) + { + perk_machine = getent( "vending_deadshot", "target" ); + } + else + { + perk_machine = getent( self.targetname, "target" ); + } + return perk_machine; +} + +get_perk_machines( zone_name ) +{ +/# + assert( isDefined( level.zones[ zone_name ] ) ); +#/ + return level.zones[ zone_name ].perk_machines; +} + +is_perk_machine_valid() +{ + trigger = self get_perk_machine_trigger(); + if ( isDefined( trigger.is_locked ) && trigger.is_locked ) + { + return 0; + } + if ( isDefined( trigger.power_on ) && trigger.power_on ) + { + return 1; + } + return 0; +} + +get_trigger_for_craftable() +{ + i = 0; + while ( i < level.a_uts_craftables.size ) + { + if ( isDefined( level.a_uts_craftables[ i ].target ) && level.a_uts_craftables[ i ].target == self.targetname ) + { + return level.a_uts_craftables[ i ]; + } + i++; + } + trig_ent = getent( self.targetname, "target" ); + return trig_ent; +} + +get_craftable_tables( zone_name ) +{ +/# + assert( isDefined( level.zones[ zone_name ] ) ); +#/ + return level.zones[ zone_name ].craftable_tables; +} + +is_craftable_table_valid() +{ + table_trig = self get_trigger_for_craftable(); + if ( isDefined( table_trig.is_locked ) && table_trig.is_locked ) + { + return 0; + } + if ( isDefined( table_trig.removed ) && table_trig.removed ) + { + return 0; + } + return 1; +} + +get_closest_trap_for_brutus() +{ + best_dist = -1; + best_trap = undefined; + i = 0; + while ( i < level.trap_triggers.size ) + { + if ( !( level.trap_triggers[ i ] [[ level.interaction_types[ "trap" ].validity_func ]]() ) ) + { + i++; + continue; + } + else + { + dist = distancesquared( self.origin, level.trap_triggers[ i ].origin ); + if ( dist < best_dist || best_dist < 0 ) + { + best_dist = dist; + best_trap = level.trap_triggers[ i ]; + } + } + i++; + } + return best_trap; +} + +get_traps( zone_name ) +{ +/# + assert( isDefined( level.zones[ zone_name ] ) ); +#/ + return level.zones[ zone_name ].traps; +} + +is_trap_valid() +{ + if ( isDefined( self.trigger.zombie_dmg_trig ) && isDefined( self.trigger.zombie_dmg_trig.active ) && self.trigger.zombie_dmg_trig.active ) + { + return 1; + } + else + { + if ( isDefined( self.trigger.active ) && self.trigger.active ) + { + return 1; + } + } + return 0; +} + +get_plane_ramps( zone_name ) +{ +/# + assert( isDefined( level.zones[ zone_name ] ) ); +#/ + return level.zones[ zone_name ].plane_triggers; +} + +is_plane_ramp_valid() +{ + if ( isDefined( self.fly_trigger ) && isDefined( self.fly_trigger.trigger_off ) && self.fly_trigger.trigger_off ) + { + return 0; + } + if ( isDefined( self.is_locked ) && self.is_locked ) + { + return 0; + } + if ( isDefined( self.equipname ) && isDefined( self.crafted ) && self.crafted ) + { + return 0; + } + return 1; +} + +get_blockers( zone_name ) +{ + return get_zone_zbarriers( zone_name ); +} + +is_blocker_valid() +{ + closed_pieces = self getzbarrierpieceindicesinstate( "closed" ); + if ( closed_pieces.size >= level.brutus_blocker_pieces_req ) + { + return 1; + } + return 0; +} + +brutus_get_closest_valid_player() +{ + valid_player_found = 0; + players = get_players(); + if ( isDefined( level._zombie_using_humangun ) && level._zombie_using_humangun ) + { + players = arraycombine( players, level._zombie_human_array, 0, 0 ); + } + while ( isDefined( self.ignore_player ) ) + { + i = 0; + while ( i < self.ignore_player.size ) + { + arrayremovevalue( players, self.ignore_player[ i ] ); + i++; + } + } + while ( !valid_player_found ) + { + if ( isDefined( level.calc_closest_player_using_paths ) && level.calc_closest_player_using_paths ) + { + player = get_closest_player_using_paths( self.origin, players ); + } + else + { + player = getclosest( self.origin, players ); + } + if ( !isDefined( player ) ) + { + return undefined; + } + if ( isDefined( level._zombie_using_humangun ) && level._zombie_using_humangun && isai( player ) ) + { + return player; + } + while ( !is_player_valid( player, 1 ) ) + { + arrayremovevalue( players, player ); + } + return player; + } +} + +watch_for_player_dist() +{ + self endon( "death" ); + while ( 1 ) + { + player = brutus_get_closest_valid_player(); + if ( !isDefined( player ) || distancesquared( player.origin, self.origin ) > level.brutus_reset_dist_sq ) + { + self.ai_state = "idle"; + self notify( "zombie_acquire_enemy" ); + self notify( "stop_find_flesh" ); + } + wait 0,5; + } +} + +brutus_goal_watcher() +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( "goal" ); + while ( self.ai_state == "find_flesh" || self.ai_state == "idle" ) + { + wait 0,05; + } + interaction = level.interaction_types[ self.ai_state ]; + origin = self.priority_item.origin; + angles = self.priority_item.angles; + if ( isDefined( interaction.interaction_z_offset ) ) + { + origin += ( 0, 0, interaction.interaction_z_offset ); + } + if ( isDefined( interaction.interaction_yaw_offset ) ) + { + angles += ( 0, interaction.interaction_yaw_offset, 0 ); + } + self.not_interruptable = 1; + self animscripted( origin, angles, interaction.animstate ); + self thread maps/mp/animscripts/zm_shared::donotetracks( interaction.notify_name ); + self thread snddointeractionvox( interaction.notify_name ); + self waittillmatch( interaction.notify_name ); + return interaction.action_notetrack; + self brutus_lockdown_client_effects(); + self thread [[ interaction.interact_func ]](); + self.priority_item = undefined; + if ( isDefined( interaction.end_notetrack ) ) + { + self waittillmatch( interaction.notify_name ); + return interaction.end_notetrack; + } + else + { + self waittillmatch( interaction.notify_name ); + return "end"; + } + self.not_interruptable = 0; + while ( !isDefined( self.priority_item ) ) + { + wait 0,05; + } + } +} + +snddointeractionvox( type ) +{ + alias = "vox_brutus_brutus_lockbox"; + num = undefined; + switch( type ) + { + case "box_lock_anim": + alias = "vox_brutus_brutus_lockbox"; + break; + case "perk_lock_anim": + alias = "vox_brutus_brutus_lockbox"; + num = 5; + break; + case "table_smash_anim": + alias = "vox_brutus_brutus_lockbox"; + num = 5; + break; + case "trap_smash_anim": + alias = "vox_brutus_brutus_lockbox"; + num = 5; + break; + case "plane_lock_anim": + alias = "vox_brutus_brutus_lockbox"; + num = 5; + break; + case "board_smash_anim": + alias = "vox_brutus_brutus_lockbox"; + num = 5; + break; + } + self thread sndbrutusvox( alias, num ); +} + +brutus_fire_teargas_when_possible() +{ + self endon( "death" ); + wait 0,2; + while ( isDefined( self.not_interruptable ) && self.not_interruptable ) + { + wait 0,05; + } + self.not_interruptable = 1; + self playsound( "vox_brutus_enraged" ); + self animscripted( self.origin, self.angles, "zm_teargas_attack" ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "teargas_anim" ); + self waittillmatch( "teargas_anim" ); + return "grenade_drop"; + v_org_left = self gettagorigin( "TAG_WEAPON_LEFT" ); + v_org_right = self gettagorigin( "TAG_WEAPON_RIGHT" ); + self thread sndplaydelayedsmokeaudio( v_org_left, v_org_right ); + self magicgrenadetype( "willy_pete_zm", v_org_left, ( 0, 0, 0 ), 0,4 ); + self magicgrenadetype( "willy_pete_zm", v_org_right, ( 0, 0, 0 ), 0,4 ); + self waittillmatch( "teargas_anim" ); + return "end"; + self.not_interruptable = 0; +} + +sndplaydelayedsmokeaudio( org1, org2 ) +{ + wait 1,5; + playsoundatposition( "zmb_ai_brutus_gas_explode", org1 ); + wait 0,25; + playsoundatposition( "zmb_ai_brutus_gas_explode", org2 ); +} + +brutus_afterlife_teleport() +{ + playfx( level._effect[ "afterlife_teleport" ], self.origin ); + self hide(); + wait 0,1; + self notify( "brutus_cleanup" ); + if ( isDefined( self.sndbrutusmusicent ) ) + { + self.sndbrutusmusicent delete(); + self.sndbrutusmusicent = undefined; + } + level thread respawn_brutus( self.health, self.has_helmet, self.helmet_hits, self.explosive_dmg_taken, self.force_zone ); + level.brutus_count--; + + self delete(); +} + +brutus_remove_helmet( vdir ) +{ + self.has_helmet = 0; + self detach( "c_zom_cellbreaker_helmet" ); + self playsound( "evt_brutus_helmet" ); + launch_pos = self.origin + vectorScale( ( 0, 0, 0 ), 85 ); + createdynentandlaunch( "c_zom_cellbreaker_helmet", launch_pos, self.angles, launch_pos, vdir ); + if ( isDefined( self.suppress_teargas_behavior ) && !self.suppress_teargas_behavior ) + { + self thread brutus_fire_teargas_when_possible(); + if ( isDefined( self.not_interruptable ) && self.not_interruptable ) + { + return; + } + self.not_interruptable = 1; + self playsound( "vox_brutus_exert" ); + self animscripted( self.origin, self.angles, "zm_pain" ); + self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" ); + self.not_interruptable = 0; + } +} + +offset_fx_struct( int_struct, fx_struct ) +{ + if ( isDefined( int_struct.fx_x_offset ) ) + { + fx_struct.origin += ( int_struct.fx_x_offset, 0, 0 ); + } + if ( isDefined( int_struct.fx_y_offset ) ) + { + fx_struct.origin += ( 0, int_struct.fx_y_offset, 0 ); + } + if ( isDefined( int_struct.fx_z_offset ) ) + { + fx_struct.origin += ( 0, 0, int_struct.fx_z_offset ); + } + if ( isDefined( int_struct.fx_yaw_offset ) ) + { + fx_struct.angles += ( 0, int_struct.fx_yaw_offset, 0 ); + } + return fx_struct; +} + +get_scaling_lock_cost( int_type, object ) +{ + interaction = level.interaction_types[ int_type ]; + base_cost = interaction.unlock_cost; + if ( !isDefined( object.num_times_locked ) ) + { + object.num_times_locked = 0; + } + object.num_times_locked++; + num_times_locked = object.num_times_locked; + if ( num_times_locked > interaction.num_times_to_scale ) + { + num_times_locked = interaction.num_times_to_scale; + } + return num_times_locked * base_cost; +} + +get_lock_hint_string( cost ) +{ + switch( cost ) + { + case 2000: + return &"ZOMBIE_LOCKED_COST_2000"; + case 4000: + return &"ZOMBIE_LOCKED_COST_4000"; + case 6000: + return &"ZOMBIE_LOCKED_COST_6000"; + default: + return &"ZOMBIE_LOCKED_COST"; + } +} + +magic_box_lock() +{ + self endon( "death" ); + if ( flag( "moving_chest_now" ) ) + { + self.priority_item = undefined; + return; + } + magic_box = self.priority_item; + if ( !isDefined( magic_box ) ) + { + return; + } + magic_box.zbarrier set_magic_box_zbarrier_state( "locking" ); + self playsound( "zmb_ai_brutus_clang" ); + magic_box.locked_cost = get_scaling_lock_cost( "magic_box", magic_box ); + level.lockdown_track[ "magic_box" ] = 1; + level notify( "brutus_locked_object" ); + self.priority_item = undefined; +} + +perk_machine_lock() +{ + self endon( "death" ); + perk_machine = self.priority_item get_perk_machine_trigger(); + if ( !isDefined( perk_machine ) ) + { + return; + } + int_struct = level.interaction_types[ "perk_machine" ]; + if ( perk_machine.target == "vending_jugg" || perk_machine.target == "vending_deadshot" ) + { + lock_fx = level._effect[ "brutus_lockdown_sm" ]; + } + else + { + lock_fx = level._effect[ "brutus_lockdown" ]; + } + perk_machine.lock_fx = spawn( "script_model", self.priority_item.origin ); + perk_machine.lock_fx.angles = self.priority_item.angles; + perk_machine.lock_fx = offset_fx_struct( int_struct, perk_machine.lock_fx ); + perk_machine.lock_fx setmodel( "tag_origin" ); + playfxontag( lock_fx, perk_machine.lock_fx, "tag_origin" ); + perk_machine.lock_fx playsound( "zmb_ai_brutus_clang" ); + perk_machine.is_locked = 1; + perk_machine.locked_cost = get_scaling_lock_cost( "perk_machine", perk_machine ); + perk_machine sethintstring( &"ZOMBIE_LOCKED_COST", perk_machine.locked_cost ); + level.lockdown_track[ perk_machine.script_string ] = 1; + level notify( "brutus_locked_object" ); + self.priority_item = undefined; +} + +craftable_table_lock() +{ + self endon( "death" ); + table_struct = self.priority_item; + if ( !isDefined( table_struct ) ) + { + return; + } + craftable_table = table_struct get_trigger_for_craftable(); + int_struct = level.interaction_types[ "craftable_table" ]; + craftable_table.lock_fx = spawn( "script_model", table_struct.origin ); + craftable_table.lock_fx.angles = table_struct.angles; + craftable_table.lock_fx = offset_fx_struct( int_struct, craftable_table.lock_fx ); + craftable_table.lock_fx setmodel( "tag_origin" ); + playfxontag( level._effect[ "brutus_lockdown_lg" ], craftable_table.lock_fx, "tag_origin" ); + craftable_table.lock_fx playsound( "zmb_ai_brutus_clang" ); + craftable_table.is_locked = 1; + craftable_table.locked_cost = get_scaling_lock_cost( "craftable_table", craftable_table ); + craftable_table.hint_string = get_lock_hint_string( craftable_table.locked_cost ); + if ( !isDefined( craftable_table.equipname ) ) + { + craftable_table sethintstring( craftable_table.hint_string ); + } + if ( isDefined( craftable_table.targetname ) && craftable_table.targetname == "blundergat_upgrade" ) + { + level.lockdown_track[ "craft_kit" ] = 1; + } + if ( isDefined( craftable_table.weaponname ) && craftable_table.weaponname == "alcatraz_shield_zm" ) + { + level.lockdown_track[ "craft_shield" ] = 1; + } + level notify( "brutus_locked_object" ); + self.priority_item = undefined; +} + +trap_smash() +{ + self endon( "death" ); + trap = self.priority_item.trigger; + if ( !isDefined( trap ) ) + { + return; + } + if ( trap.targetname == "fan_trap_use_trigger" ) + { + trap.zombie_dmg_trig notify( "trap_finished_" + trap.script_string ); + } + else if ( trap.targetname == "acid_trap_trigger" ) + { + trap.zombie_dmg_trig notify( "acid_trap_fx_done" ); + } + else + { + if ( trap.targetname == "tower_trap_activate_trigger" ) + { + trap notify( "tower_trap_off" ); + } + } + trap playsound( "zmb_ai_brutus_clang" ); + self.priority_item = undefined; +} + +plane_ramp_lock() +{ + self endon( "death" ); + plane_ramp = self.priority_item; + if ( !isDefined( plane_ramp ) ) + { + return; + } + int_struct = level.interaction_types[ "plane_ramp" ]; + plane_ramp.lock_fx = spawn( "script_model", plane_ramp.origin ); + plane_ramp.lock_fx.angles = plane_ramp.angles; + plane_ramp.lock_fx = offset_fx_struct( int_struct, plane_ramp.lock_fx ); + plane_ramp.lock_fx setmodel( "tag_origin" ); + plane_ramp.lock_fx playsound( "zmb_ai_brutus_clang" ); + playfxontag( level._effect[ "brutus_lockdown" ], plane_ramp.lock_fx, "tag_origin" ); + plane_ramp.is_locked = 1; + plane_ramp.locked_cost = get_scaling_lock_cost( "plane_ramp", plane_ramp ); + plane_ramp.hint_string = get_lock_hint_string( plane_ramp.locked_cost ); + plane_ramp maps/mp/zombies/_zm_unitrigger::run_visibility_function_for_all_triggers(); + level.lockdown_track[ "plane_ramp" ] = 1; + level notify( "brutus_locked_object" ); + if ( !isDefined( plane_ramp.equipname ) ) + { + plane_ramp.fly_trigger sethintstring( plane_ramp.hint_string ); + } +} + +blocker_smash() +{ + self endon( "death" ); + self playsound( "vox_brutus_enraged" ); + self playsound( "zmb_ai_brutus_window_teardown" ); + blocker = self.priority_item; + self playsound( "zmb_ai_brutus_clang" ); + if ( !isDefined( blocker ) ) + { + return; + } + num_pieces = blocker getnumzbarrierpieces(); + i = 0; + while ( i < num_pieces ) + { + blocker hidezbarrierpiece( i ); + blocker setzbarrierpiecestate( i, "open" ); + i++; + } + if ( !isDefined( blocker.script_string ) ) + { + smash_fx_alias = "brutus_smash_default"; + } + else + { + smash_fx_alias = "brutus_smash_" + blocker.script_string; + } + forward = anglesToForward( blocker.angles + vectorScale( ( 0, 0, 0 ), 180 ) ); + if ( isDefined( level._effect[ smash_fx_alias ] ) ) + { + playfx( level._effect[ smash_fx_alias ], blocker.origin, forward ); + } + else + { + playfx( level._effect[ "brutus_smash_default" ], blocker.origin, forward ); + } + self.priority_item = undefined; +} + +melee_anim_func() +{ + self.next_leap_time = getTime() + 1500; +} + +kill_teargas_after_duration( duration ) +{ + wait duration; + self notify( "kill_teargas" ); + wait_network_frame(); + self delete(); +} + +teargas_player( player ) +{ + player endon( "death_or_disconnect" ); + level endon( "intermission" ); + self endon( "kill_teargas" ); + player.being_teargassed = 1; + clear_timer = 0; + teargas_timer = 0; + while ( 1 ) + { + self waittill( "trigger", player ); + while ( 1 ) + { + if ( !player istouching( self ) ) + { + clear_timer += 0,1; + } + else + { + clear_timer = 0; + } + if ( clear_timer >= level.player_teargas_duration ) + { + player.being_teargassed = 0; + break; + } + else if ( ( teargas_timer % 5 ) == 0 ) + { + if ( distancesquared( player.origin, self.origin ) > ( ( ( level.brutus_teargas_radius * 2 ) / 3 ) * ( ( level.brutus_teargas_radius * 2 ) / 3 ) ) ) + { + player shellshock( "mp_radiation_low", 1,5 ); + teargas_timer++; + continue; + } + else if ( distancesquared( player.origin, self.origin ) > ( ( ( level.brutus_teargas_radius * 1 ) / 3 ) * ( ( level.brutus_teargas_radius * 1 ) / 3 ) ) ) + { + player shellshock( "mp_radiation_med", 1,5 ); + teargas_timer++; + continue; + } + else + { + player shellshock( "mp_radiation_high", 1,5 ); + } + } + teargas_timer++; + wait 0,1; + } + } +} + +teargas_trigger_think() +{ + self endon( "kill_teargas" ); + self thread kill_teargas_after_duration( level.brutus_teargas_duration ); + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( isDefined( players[ i ].being_teargassed ) && !players[ i ].being_teargassed ) + { + self thread teargas_player( players[ i ] ); + } + i++; + } +} + +precache_default_brutus_barrier_fx() +{ + level._effect[ "brutus_smash_default" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_brut_brk_wood" ); +} + +scale_helmet_damage( attacker, damage, headshot_mod, damage_mod, vdir ) +{ + if ( !self.has_helmet ) + { + return damage * headshot_mod; + } + else + { + self.helmet_hits++; + if ( self.helmet_hits >= level.brutus_helmet_shots ) + { + self thread brutus_remove_helmet( vdir ); + if ( level.brutus_in_grief ) + { + player_points = level.brutus_points_for_helmet; + } + else + { + multiplier = maps/mp/zombies/_zm_score::get_points_multiplier( self ); + player_points = multiplier * round_up_score( level.brutus_points_for_helmet, 5 ); + } + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + attacker add_to_player_score( player_points ); + attacker.pers[ "score" ] = attacker.score; + level notify( "brutus_helmet_removed" ); + } + } + return damage * damage_mod; + } +} + +brutus_non_attacker_damage_override( damage, weapon ) +{ + scaled_dmg = 0; + if ( weapon == "tower_trap_zm" ) + { + scaled_dmg = self scale_helmet_damage( undefined, damage, 0,1, 0,01, vectorScale( ( 0, 0, 0 ), 10 ) ); + } + return int( scaled_dmg ); +} + +is_weapon_shotgun( sweapon ) +{ + if ( weaponclass( sweapon ) == "spread" ) + { + return 1; + } + return 0; +} + +brutus_damage_override( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, poffsettime, boneindex ) +{ + if ( isDefined( attacker ) && isalive( attacker ) && isplayer( attacker ) || level.zombie_vars[ attacker.team ][ "zombie_insta_kill" ] && isDefined( attacker.personal_instakill ) && attacker.personal_instakill ) + { + n_brutus_damage_percent = 1; + n_brutus_headshot_modifier = 2; + } + else + { + n_brutus_damage_percent = level.brutus_damage_percent; + n_brutus_headshot_modifier = 1; + } + if ( isDefined( weapon ) && is_weapon_shotgun( weapon ) ) + { + n_brutus_damage_percent *= level.brutus_shotgun_damage_mod; + n_brutus_headshot_modifier *= level.brutus_shotgun_damage_mod; + } + if ( isDefined( weapon ) && weapon == "bouncing_tomahawk_zm" && isDefined( inflictor ) ) + { + self playsound( "wpn_tomahawk_imp_zombie" ); + if ( self.has_helmet ) + { + if ( damage == 1 ) + { + return 0; + } + if ( isDefined( inflictor.n_cookedtime ) && inflictor.n_cookedtime >= 2000 ) + { + self.helmet_hits = level.brutus_helmet_shots; + } + else + { + if ( isDefined( inflictor.n_grenade_charge_power ) && inflictor.n_grenade_charge_power >= 2 ) + { + self.helmet_hits = level.brutus_helmet_shots; + } + else + { + self.helmet_hits++; + } + } + if ( self.helmet_hits >= level.brutus_helmet_shots ) + { + self thread brutus_remove_helmet( vdir ); + if ( level.brutus_in_grief ) + { + player_points = level.brutus_points_for_helmet; + } + else + { + multiplier = maps/mp/zombies/_zm_score::get_points_multiplier( self ); + player_points = multiplier * round_up_score( level.brutus_points_for_helmet, 5 ); + } + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + attacker add_to_player_score( player_points ); + attacker.pers[ "score" ] = attacker.score; + level notify( "brutus_helmet_removed" ); + } + } + return damage * n_brutus_damage_percent; + } + else + { + return damage; + } + } + if ( isDefined( meansofdeath ) || meansofdeath == "MOD_MELEE" && meansofdeath == "MOD_IMPACT" ) + { + if ( weapon == "alcatraz_shield_zm" ) + { + shield_damage = level.zombie_vars[ "riotshield_fling_damage_shield" ]; + inflictor maps/mp/zombies/_zm_weap_riotshield_prison::player_damage_shield( shield_damage, 0 ); + return 0; + } + } + if ( isDefined( level.zombiemode_using_afterlife ) && level.zombiemode_using_afterlife && weapon == "lightning_hands_zm" ) + { + self thread brutus_afterlife_teleport(); + return 0; + } + if ( is_explosive_damage( meansofdeath ) ) + { + self.explosive_dmg_taken += damage; + if ( !self.has_helmet ) + { + scaler = n_brutus_headshot_modifier; + } + else + { + scaler = level.brutus_damage_percent; + } + if ( self.explosive_dmg_taken >= self.explosive_dmg_req && isDefined( self.has_helmet ) && self.has_helmet ) + { + self thread brutus_remove_helmet( vectorScale( ( 0, 0, 0 ), 10 ) ); + if ( level.brutus_in_grief ) + { + player_points = level.brutus_points_for_helmet; + } + else + { + multiplier = maps/mp/zombies/_zm_score::get_points_multiplier( self ); + player_points = multiplier * round_up_score( level.brutus_points_for_helmet, 5 ); + } + attacker add_to_player_score( player_points ); + attacker.pers[ "score" ] = inflictor.score; + } + return damage * scaler; + } + else + { + if ( shitloc != "head" && shitloc != "helmet" ) + { + return damage * n_brutus_damage_percent; + } + else + { + return int( self scale_helmet_damage( attacker, damage, n_brutus_headshot_modifier, n_brutus_damage_percent, vdir ) ); + } + } +} + +brutus_instakill_override() +{ + return; +} + +brutus_nuke_override() +{ + self endon( "death" ); + wait randomfloatrange( 0,1, 0,7 ); + self thread maps/mp/animscripts/zm_death::flame_death_fx(); + self playsound( "evt_nuked" ); + self dodamage( level.brutus_health * 0,25, self.origin ); + return; +} + +custom_brutus_flame_death_fx() +{ + self endon( "death" ); + if ( isDefined( self.is_on_fire ) && self.is_on_fire ) + { + return; + } + self.is_on_fire = 1; + a_script_origins = []; + if ( isDefined( level._effect ) && isDefined( level._effect[ "character_fire_death_torso" ] ) ) + { + if ( !self.isdog ) + { + v_origin = self gettagorigin( "J_SpineLower" ); + e_origin = spawn( "script_origin", v_origin ); + e_origin setmodel( "tag_origin" ); + e_origin linkto( self, "J_SpineLower" ); + playfxontag( level._effect[ "character_fire_death_torso" ], e_origin, "tag_origin" ); + a_script_origins[ a_script_origins.size ] = e_origin; + } + } + else + { +/# + println( "^3ANIMSCRIPT WARNING: You are missing level._effect["character_fire_death_torso"], please set it in your levelname_fx.gsc. Use "env/fire/fx_fire_player_torso"" ); +#/ + } + if ( isDefined( level._effect ) && isDefined( level._effect[ "character_fire_death_sm" ] ) ) + { + wait 1; + tagarray = []; + tagarray[ 0 ] = "J_Elbow_LE"; + tagarray[ 1 ] = "J_Elbow_RI"; + tagarray[ 2 ] = "J_Knee_RI"; + tagarray[ 3 ] = "J_Knee_LE"; + tagarray = maps/mp/animscripts/zm_death::randomize_array( tagarray ); + v_origin = self gettagorigin( tagarray[ 0 ] ); + e_origin = spawn( "script_origin", v_origin ); + e_origin setmodel( "tag_origin" ); + e_origin linkto( self, tagarray[ 0 ] ); + playfxontag( level._effect[ "character_fire_death_torso" ], e_origin, "tag_origin" ); + a_script_origins[ a_script_origins.size ] = e_origin; + wait 1; + tagarray[ 0 ] = "J_Wrist_RI"; + tagarray[ 1 ] = "J_Wrist_LE"; + if ( isDefined( self.a ) || !isDefined( self.a.gib_ref ) && self.a.gib_ref != "no_legs" ) + { + tagarray[ 2 ] = "J_Ankle_RI"; + tagarray[ 3 ] = "J_Ankle_LE"; + } + tagarray = maps/mp/animscripts/zm_death::randomize_array( tagarray ); + v_origin_0 = self gettagorigin( tagarray[ 0 ] ); + v_origin_1 = self gettagorigin( tagarray[ 1 ] ); + e_origin_0 = spawn( "script_origin", v_origin_0 ); + e_origin_1 = spawn( "script_origin", v_origin_1 ); + e_origin_0 setmodel( "tag_origin" ); + e_origin_1 setmodel( "tag_origin" ); + e_origin_0 linkto( self, tagarray[ 0 ] ); + e_origin_1 linkto( self, tagarray[ 1 ] ); + playfxontag( level._effect[ "character_fire_death_torso" ], e_origin_0, "tag_origin" ); + playfxontag( level._effect[ "character_fire_death_torso" ], e_origin_1, "tag_origin" ); + a_script_origins[ a_script_origins.size ] = e_origin_0; + a_script_origins[ a_script_origins.size ] = e_origin_1; + } + else + { +/# + println( "^3ANIMSCRIPT WARNING: You are missing level._effect["character_fire_death_sm"], please set it in your levelname_fx.gsc. Use "env/fire/fx_fire_zombie_md"" ); +#/ + } + self thread custom_brutus_on_fire_timeout( a_script_origins ); +} + +custom_brutus_on_fire_timeout( a_script_origins ) +{ + self endon( "death" ); + wait 3; + if ( isDefined( self ) && isalive( self ) ) + { + self.is_on_fire = 0; + self notify( "stop_flame_damage" ); + } + _a2804 = a_script_origins; + _k2804 = getFirstArrayKey( _a2804 ); + while ( isDefined( _k2804 ) ) + { + script_origin = _a2804[ _k2804 ]; + script_origin delete(); + _k2804 = getNextArrayKey( _a2804, _k2804 ); + } +} + +brutus_debug() +{ +/# + while ( 1 ) + { + debug_level = getDvarInt( #"8DB11170" ); + while ( isDefined( debug_level ) && debug_level ) + { + while ( debug_level == 1 ) + { + brutus_array = getentarray( "brutus_zombie_ai" ); + i = 0; + while ( i < brutus_array.size ) + { + if ( isDefined( brutus_array[ i ].goal_pos ) ) + { + debugstar( brutus_array[ i ].goal_pos, ( 0, 0, 0 ), 1 ); + line( brutus_array[ i ].goal_pos, brutus_array[ i ].origin, ( 0, 0, 0 ), 0, 1 ); + } + i++; + } + } + } +#/ + } +} + +brutus_check_zone() +{ + self endon( "death" ); + self.in_player_zone = 0; + while ( 1 ) + { + self.in_player_zone = 0; + _a2851 = level.zones; + _k2851 = getFirstArrayKey( _a2851 ); + while ( isDefined( _k2851 ) ) + { + zone = _a2851[ _k2851 ]; + if ( !isDefined( zone.volumes ) || zone.volumes.size == 0 ) + { + } + else + { + zone_name = zone.volumes[ 0 ].targetname; + if ( self maps/mp/zombies/_zm_zonemgr::entity_in_zone( zone_name ) ) + { + if ( is_true( zone.is_occupied ) ) + { + self.in_player_zone = 1; + break; + } + } + } + else + { + _k2851 = getNextArrayKey( _a2851, _k2851 ); + } + } + wait 0,2; + } +} + +brutus_watch_enemy() +{ + self endon( "death" ); + while ( 1 ) + { + if ( !is_player_valid( self.favoriteenemy ) ) + { + self.favoriteenemy = get_favorite_enemy(); + } + wait 0,2; + } +} + +get_favorite_enemy() +{ + brutus_targets = getplayers(); + least_hunted = brutus_targets[ 0 ]; + i = 0; + while ( i < brutus_targets.size ) + { + if ( !isDefined( brutus_targets[ i ].hunted_by ) ) + { + brutus_targets[ i ].hunted_by = 0; + } + if ( !is_player_valid( brutus_targets[ i ] ) ) + { + i++; + continue; + } + else + { + if ( !is_player_valid( least_hunted ) ) + { + least_hunted = brutus_targets[ i ]; + } + if ( brutus_targets[ i ].hunted_by < least_hunted.hunted_by ) + { + least_hunted = brutus_targets[ i ]; + } + } + i++; + } + least_hunted.hunted_by += 1; + return least_hunted; +} + +brutus_lockdown_client_effects( delay ) +{ + self endon( "death" ); + if ( isDefined( delay ) ) + { + wait delay; + } + if ( self.brutus_lockdown_state ) + { + self.brutus_lockdown_state = 0; + self setclientfield( "brutus_lock_down", 0 ); + } + else + { + self.brutus_lockdown_state = 1; + self setclientfield( "brutus_lock_down", 1 ); + } +} + +get_brutus_interest_points() +{ + zone_names = getarraykeys( level.zones ); + i = 0; + while ( i < zone_names.size ) + { + self thread get_zone_perk_machines( zone_names[ i ] ); + self thread get_zone_craftable_tables( zone_names[ i ] ); + self thread get_zone_traps( zone_names[ i ] ); + self thread get_zone_plane_ramp( zone_names[ i ] ); + i++; + } + build_trap_array(); + flag_set( "brutus_setup_complete" ); +} + +build_trap_array() +{ + fan_array = getentarray( "acid_trap_trigger", "targetname" ); + acid_array = getentarray( "fan_trap_use_trigger", "targetname" ); + level.trap_triggers = arraycombine( fan_array, acid_array, 0, 0 ); +} + +add_machines_in_zone( zone, zone_name, match_string ) +{ + machine_array = getentarray( match_string, "targetname" ); + i = 0; + while ( i < machine_array.size ) + { + if ( machine_array[ i ] entity_in_zone( zone_name, 1 ) ) + { + zone.perk_machines[ zone.perk_machines.size ] = machine_array[ i ]; + } + i++; + } +} + +get_zone_perk_machines( zone_name ) +{ + zone = level.zones[ zone_name ]; + zone.perk_machines = []; + machine_array = []; + if ( isDefined( level.zombiemode_using_doubletap_perk ) && level.zombiemode_using_doubletap_perk ) + { + add_machines_in_zone( zone, zone_name, "vending_doubletap" ); + } + if ( isDefined( level.zombiemode_using_revive_perk ) && level.zombiemode_using_revive_perk ) + { + add_machines_in_zone( zone, zone_name, "vending_revive" ); + } + if ( isDefined( level.zombiemode_using_juggernaut_perk ) && level.zombiemode_using_juggernaut_perk ) + { + add_machines_in_zone( zone, zone_name, "vending_jugg" ); + } + if ( isDefined( level.zombiemode_using_sleightofhand_perk ) && level.zombiemode_using_sleightofhand_perk ) + { + add_machines_in_zone( zone, zone_name, "vending_sleight" ); + } + if ( isDefined( level.zombiemode_using_deadshot_perk ) && level.zombiemode_using_deadshot_perk ) + { + add_machines_in_zone( zone, zone_name, "vending_deadshot_model" ); + } + if ( isDefined( level.zombiemode_using_electric_cherry_perk ) && level.zombiemode_using_electric_cherry_perk ) + { + add_machines_in_zone( zone, zone_name, "vendingelectric_cherry" ); + } + if ( isDefined( level.zombiemode_using_additionalprimaryweapon_perk ) && level.zombiemode_using_additionalprimaryweapon_perk ) + { + add_machines_in_zone( zone, zone_name, "vending_additionalprimaryweapon" ); + } + if ( isDefined( level.zombiemode_using_marathon_perk ) && level.zombiemode_using_marathon_perk ) + { + add_machines_in_zone( zone, zone_name, "vending_marathon" ); + } + if ( isDefined( level.zombiemode_using_divetonuke_perk ) && level.zombiemode_using_divetonuke_perk ) + { + add_machines_in_zone( zone, zone_name, "vending_divetonuke" ); + } + if ( isDefined( level.zombiemode_using_chugabud_perk ) && level.zombiemode_using_chugabud_perk ) + { + add_machines_in_zone( zone, zone_name, "vending_chugabud" ); + } +} + +get_zone_craftable_tables( zone_name ) +{ + flag_wait( "initial_players_connected" ); + zone = level.zones[ zone_name ]; + zone.craftable_tables = []; + while ( level.a_uts_craftables.size == 0 ) + { + wait 1; + } + scr_org = spawn( "script_origin", ( 0, 0, 0 ) ); + craftable_tables = level.a_uts_craftables; + i = 0; + while ( i < craftable_tables.size ) + { + if ( !isDefined( craftable_tables[ i ].origin ) ) + { + i++; + continue; + } + else + { + scr_org.origin = craftable_tables[ i ].origin; + wait 0,05; + if ( craftable_tables[ i ].equipname == "open_table" && scr_org entity_in_zone( zone_name, 1 ) ) + { + zone.craftable_tables[ zone.craftable_tables.size ] = getstruct( craftable_tables[ i ].target, "targetname" ); + } + } + i++; + } + scr_org delete(); +} + +get_zone_traps( zone_name ) +{ + zone = level.zones[ zone_name ]; + zone.traps = []; + acid_traps = getentarray( "acid_trap_trigger", "targetname" ); + scr_org = spawn( "script_origin", ( 0, 0, 0 ) ); + i = 0; + while ( i < acid_traps.size ) + { + target_struct = getstruct( acid_traps[ i ].script_parameters, "targetname" ); + acid_traps[ i ].target_struct = target_struct; + scr_org.origin = target_struct.origin; + wait 0,05; + if ( scr_org entity_in_zone( zone_name, 1 ) ) + { + zone.traps[ zone.traps.size ] = acid_traps[ i ].target_struct; + target_struct.trigger = acid_traps[ i ]; + } + i++; + } + fan_traps = getentarray( "fan_trap_use_trigger", "targetname" ); + i = 0; + while ( i < fan_traps.size ) + { + target_struct = getstruct( fan_traps[ i ].script_parameters, "targetname" ); + fan_traps[ i ].target_struct = target_struct; + scr_org.origin = target_struct.origin; + wait 0,05; + if ( scr_org entity_in_zone( zone_name, 1 ) ) + { + zone.traps[ zone.traps.size ] = fan_traps[ i ].target_struct; + target_struct.trigger = fan_traps[ i ]; + } + i++; + } + tower_traps = getentarray( "tower_trap_activate_trigger", "targetname" ); + i = 0; + while ( i < tower_traps.size ) + { + target_struct = getstruct( tower_traps[ i ].script_parameters, "targetname" ); + tower_traps[ i ].target_struct = target_struct; + scr_org.origin = target_struct.origin; + wait 0,05; + if ( scr_org entity_in_zone( zone_name, 1 ) ) + { + zone.traps[ zone.traps.size ] = tower_traps[ i ].target_struct; + target_struct.trigger = tower_traps[ i ]; + } + i++; + } + scr_org delete(); +} + +get_zone_plane_ramp( zone_name ) +{ + flag_wait( "initial_players_connected" ); + zone = level.zones[ zone_name ]; + zone.plane_triggers = []; + scr_org = spawn( "script_origin", ( 0, 0, 0 ) ); + fly_trigger = getent( "plane_fly_trigger", "targetname" ); + scr_org.origin = fly_trigger.origin; + if ( scr_org entity_in_zone( zone_name, 1 ) ) + { + fly_trigger_target = spawn( "script_model", ( 0, 0, 0 ) ); + fly_trigger_target.targetname = "fly_target"; + fly_trigger.fly_trigger_target = fly_trigger_target; + fly_trigger_target.fly_trigger = fly_trigger; + zone.plane_triggers[ zone.plane_triggers.size ] = fly_trigger_target; + } + while ( level.a_uts_craftables.size == 0 ) + { + wait 1; + } + i = 0; + while ( i < level.a_uts_craftables.size ) + { + if ( level.a_uts_craftables[ i ].equipname == "plane" ) + { + scr_org.origin = level.a_uts_craftables[ i ].origin; + wait 0,05; + if ( scr_org entity_in_zone( zone_name, 1 ) ) + { + zone.plane_triggers[ zone.plane_triggers.size ] = level.a_uts_craftables[ i ]; + fly_trigger_target.origin = level.a_uts_craftables[ i ].origin; + fly_trigger_target.angles = level.a_uts_craftables[ i ].angles; + } + } + i++; + } + scr_org delete(); +} + +check_magic_box_valid( player ) +{ + if ( isDefined( self.is_locked ) && self.is_locked ) + { + if ( player.score >= self.locked_cost ) + { + player minus_to_player_score( self.locked_cost ); + self.is_locked = 0; + self.locked_cost = undefined; + self.zbarrier set_magic_box_zbarrier_state( "unlocking" ); + } + return 0; + } + return 1; +} + +check_perk_machine_valid( player ) +{ + if ( isDefined( self.is_locked ) && self.is_locked ) + { + if ( player.score >= self.locked_cost ) + { + player minus_to_player_score( self.locked_cost ); + self.is_locked = 0; + self.locked_cost = undefined; + self.lock_fx delete(); + self maps/mp/zombies/_zm_perks::reset_vending_hint_string(); + } + return 0; + } + return 1; +} + +check_craftable_table_valid( player ) +{ + if ( !isDefined( self.stub ) && isDefined( self.is_locked ) && self.is_locked ) + { + if ( player.score >= self.locked_cost ) + { + player minus_to_player_score( self.locked_cost ); + self.is_locked = 0; + self.locked_cost = undefined; + self.lock_fx delete(); + } + return 0; + } + else + { + if ( isDefined( self.stub ) && isDefined( self.stub.is_locked ) && self.stub.is_locked ) + { + if ( player.score >= self.stub.locked_cost ) + { + player minus_to_player_score( self.stub.locked_cost ); + self.stub.is_locked = 0; + self.stub.locked_cost = undefined; + self.stub.lock_fx delete(); + self.stub thread maps/mp/zombies/_zm_craftables::craftablestub_update_prompt( player ); + self sethintstring( self.stub.hint_string ); + } + return 0; + } + } + return 1; +} + +check_plane_valid( player ) +{ + if ( isDefined( self.fly_trigger_target ) ) + { + plane_struct = self.fly_trigger_target; + } + else + { + plane_struct = self; + } + if ( isDefined( plane_struct.is_locked ) && plane_struct.is_locked ) + { + if ( player.score >= plane_struct.locked_cost ) + { + player minus_to_player_score( plane_struct.locked_cost ); + plane_struct.is_locked = 0; + plane_struct.locked_cost = undefined; + plane_struct.lock_fx delete(); + plane_struct maps/mp/zm_alcatraz_sq::reset_plane_hint_string( player ); + } + return 0; + } + return 1; +} + +sndbrutusvox( alias, num ) +{ + self endon( "brutus_cleanup" ); + if ( !isDefined( alias ) ) + { + return; + } + num_variants = maps/mp/zombies/_zm_spawner::get_number_variants( alias ); + if ( num_variants <= 0 ) + { + return; + } + if ( isDefined( num ) && num <= num_variants ) + { + num_variants = num; + } + if ( !level.sndbrutusistalking ) + { + level.sndbrutusistalking = 1; + alias = ( alias + "_" ) + randomintrange( 0, num_variants ); + playbacktime = soundgetplaybacktime( alias ); + if ( playbacktime >= 0 ) + { + playbacktime *= 0,001; + } + else + { + playbacktime = 1; + } + self playsoundontag( alias, "J_head" ); + wait playbacktime; + level.sndbrutusistalking = 0; + } +} + +get_fly_trigger() +{ + plane_triggers = level.zones[ "zone_roof" ].plane_triggers; + i = 0; + while ( i < plane_triggers.size ) + { + if ( isDefined( plane_triggers[ i ].fly_trigger ) ) + { + return plane_triggers[ i ]; + } + i++; + } +} + +get_build_trigger() +{ + plane_triggers = level.zones[ "zone_roof" ].plane_triggers; + i = 0; + while ( i < plane_triggers.size ) + { + if ( isDefined( plane_triggers[ i ].equipname ) && plane_triggers[ i ].equipname == "plane" ) + { + return plane_triggers[ i ]; + } + i++; + } +} + +get_fuel_trigger() +{ + plane_triggers = level.zones[ "zone_roof" ].plane_triggers; + i = 0; + while ( i < plane_triggers.size ) + { + if ( isDefined( plane_triggers[ i ].equipname ) && plane_triggers[ i ].equipname == "refuelable_plane" ) + { + return plane_triggers[ i ]; + } + i++; + } +} + +transfer_plane_trigger( from, to ) +{ + if ( from == "fly" ) + { + from_trigger = get_fly_trigger(); + } + else if ( from == "build" ) + { + from_trigger = get_build_trigger(); + } + else + { + from_trigger = get_fuel_trigger(); + } + if ( to == "fly" ) + { + to_trigger = get_fly_trigger(); + } + else if ( to == "build" ) + { + to_trigger = get_build_trigger(); + } + else + { + to_trigger = get_fuel_trigger(); + } + to_trigger.lock_fx = from_trigger.lock_fx; + to_trigger.is_locked = from_trigger.is_locked; + to_trigger.num_times_locked = from_trigger.num_times_locked; + to_trigger.hint_string = from_trigger.hint_string; + to_trigger.locked_cost = from_trigger.locked_cost; + from_trigger.lock_fx = undefined; + from_trigger.is_locked = 0; + from_trigger.locked_cost = undefined; + if ( from == "fly" ) + { + t_plane_fly = getent( "plane_fly_trigger", "targetname" ); + t_plane_fly sethintstring( &"ZM_PRISON_PLANE_BOARD" ); + } +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_craftables.gsc b/zm_prison_patch/maps/mp/zombies/_zm_craftables.gsc new file mode 100644 index 0000000..fec7059 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_craftables.gsc @@ -0,0 +1,3192 @@ +#include maps/mp/_demo; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + precachestring( &"ZOMBIE_BUILDING" ); + precachestring( &"ZOMBIE_BUILD_PIECE_MISSING" ); + precachestring( &"ZOMBIE_BUILD_PIECE_GRAB" ); + precacheitem( "zombie_builder_zm" ); + precacheitem( "buildable_piece_zm" ); + level.craftable_piece_swap_allowed = 1; + zombie_craftables_callbacks = []; + level.craftablepickups = []; + level.craftables_crafted = []; + level.a_uts_craftables = []; + level.craftable_piece_count = 0; + level._effect[ "building_dust" ] = loadfx( "maps/zombie/fx_zmb_buildable_assemble_dust" ); + if ( isDefined( level.init_craftables ) ) + { + [[ level.init_craftables ]](); + } + open_table = spawnstruct(); + open_table.name = "open_table"; + open_table.triggerthink = ::opentablecraftable; + open_table.custom_craftablestub_update_prompt = ::open_craftablestub_update_prompt; + include_zombie_craftable( open_table ); + add_zombie_craftable( "open_table", &"" ); + if ( isDefined( level.use_swipe_protection ) ) + { + onplayerconnect_callback( ::craftables_watch_swipes ); + } +} + +anystub_update_prompt( player ) +{ + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() || player in_revive_trigger() ) + { + self.hint_string = ""; + return 0; + } + if ( isDefined( player.is_drinking ) && player.is_drinking > 0 ) + { + self.hint_string = ""; + return 0; + } + if ( isDefined( player.screecher_weapon ) ) + { + self.hint_string = ""; + return 0; + } + return 1; +} + +anystub_get_unitrigger_origin() +{ + if ( isDefined( self.origin_parent ) ) + { + return self.origin_parent.origin; + } + return self.origin; +} + +anystub_on_spawn_trigger( trigger ) +{ + if ( isDefined( self.link_parent ) ) + { + trigger enablelinkto(); + trigger linkto( self.link_parent ); + trigger setmovingplatformenabled( 1 ); + } +} + +craftables_watch_swipes() +{ + self endon( "disconnect" ); + self notify( "craftables_watch_swipes" ); + self endon( "craftables_watch_swipes" ); + while ( 1 ) + { + self waittill( "melee_swipe", zombie ); + while ( distancesquared( zombie.origin, self.origin ) > ( zombie.meleeattackdist * zombie.meleeattackdist ) ) + { + continue; + } + trigger = level._unitriggers.trigger_pool[ self getentitynumber() ]; + if ( isDefined( trigger ) && isDefined( trigger.stub.piece ) ) + { + piece = trigger.stub.piece; + if ( !isDefined( piece.damage ) ) + { + piece.damage = 0; + } + piece.damage++; + if ( piece.damage > 12 ) + { + thread maps/mp/zombies/_zm_equipment::equipment_disappear_fx( trigger.stub maps/mp/zombies/_zm_unitrigger::unitrigger_origin() ); + piece maps/mp/zombies/_zm_craftables::piece_unspawn(); + self maps/mp/zombies/_zm_stats::increment_client_stat( "cheat_total", 0 ); + if ( isalive( self ) ) + { + self playlocalsound( level.zmb_laugh_alias ); + } + } + } + } +} + +explosiondamage( damage, pos ) +{ +/# + println( "ZM CRAFTABLE Explode do " + damage + " damage to " + self.name + "\n" ); +#/ + self dodamage( damage, pos ); +} + +make_zombie_craftable_open( str_craftable, str_model, v_angle_offset, v_origin_offset ) +{ +/# + assert( isDefined( level.zombie_craftablestubs[ str_craftable ] ), "Craftable " + str_craftable + " has not been added yet." ); +#/ + precachemodel( str_model ); + s_craftable = level.zombie_craftablestubs[ str_craftable ]; + s_craftable.is_open_table = 1; + s_craftable.str_model = str_model; + s_craftable.v_angle_offset = v_angle_offset; + s_craftable.v_origin_offset = v_origin_offset; +} + +add_zombie_craftable( craftable_name, str_to_craft, str_crafting, str_taken, onfullycrafted, need_all_pieces ) +{ + if ( !isDefined( level.zombie_include_craftables ) ) + { + level.zombie_include_craftables = []; + } + if ( isDefined( level.zombie_include_craftables ) && !isDefined( level.zombie_include_craftables[ craftable_name ] ) ) + { + return; + } + if ( isDefined( str_to_craft ) ) + { + precachestring( str_to_craft ); + } + if ( isDefined( str_crafting ) ) + { + precachestring( str_crafting ); + } + if ( isDefined( str_taken ) ) + { + precachestring( str_taken ); + } + craftable_struct = level.zombie_include_craftables[ craftable_name ]; + if ( !isDefined( level.zombie_craftablestubs ) ) + { + level.zombie_craftablestubs = []; + } + craftable_struct.str_to_craft = str_to_craft; + craftable_struct.str_crafting = str_crafting; + craftable_struct.str_taken = str_taken; + craftable_struct.onfullycrafted = onfullycrafted; + craftable_struct.need_all_pieces = need_all_pieces; +/# + println( "ZM >> Looking for craftable - " + craftable_struct.name ); +#/ + level.zombie_craftablestubs[ craftable_struct.name ] = craftable_struct; + if ( !level.createfx_enabled ) + { + if ( level.zombie_craftablestubs.size == 2 ) + { + bits = getminbitcountfornum( level.craftable_piece_count ); + registerclientfield( "toplayer", "craftable", 9000, bits, "int" ); + } + } +} + +add_zombie_craftable_vox_category( craftable_name, vox_id ) +{ + craftable_struct = level.zombie_include_craftables[ craftable_name ]; + craftable_struct.vox_id = vox_id; +} + +include_zombie_craftable( craftablestub ) +{ + if ( !isDefined( level.zombie_include_craftables ) ) + { + level.zombie_include_craftables = []; + } +/# + println( "ZM >> Including craftable - " + craftablestub.name ); +#/ + level.zombie_include_craftables[ craftablestub.name ] = craftablestub; +} + +generate_zombie_craftable_piece( craftablename, piecename, modelname, radius, height, drop_offset, hud_icon, onpickup, ondrop, oncrafted, use_spawn_num, tag_name, can_reuse, client_field_value, is_shared, vox_id ) +{ + if ( !isDefined( is_shared ) ) + { + is_shared = 0; + } + precachemodel( modelname ); + if ( isDefined( hud_icon ) ) + { + precacheshader( hud_icon ); + } + piecestub = spawnstruct(); + craftable_pieces = []; + piece_alias = ""; + if ( !isDefined( piecename ) ) + { + piecename = modelname; + } + craftable_pieces_structs = getstructarray( ( craftablename + "_" ) + piecename, "targetname" ); +/# + if ( craftable_pieces_structs.size < 1 ) + { + println( "ERROR: Missing craftable piece <" + craftablename + "> <" + piecename + ">\n" ); +#/ + } + _a344 = craftable_pieces_structs; + index = getFirstArrayKey( _a344 ); + while ( isDefined( index ) ) + { + struct = _a344[ index ]; + craftable_pieces[ index ] = struct; + craftable_pieces[ index ].hasspawned = 0; + index = getNextArrayKey( _a344, index ); + } + piecestub.spawns = craftable_pieces; + piecestub.craftablename = craftablename; + piecestub.piecename = piecename; + piecestub.modelname = modelname; + piecestub.hud_icon = hud_icon; + piecestub.radius = radius; + piecestub.height = height; + piecestub.tag_name = tag_name; + piecestub.can_reuse = can_reuse; + piecestub.drop_offset = drop_offset; + piecestub.max_instances = 256; + piecestub.onpickup = onpickup; + piecestub.ondrop = ondrop; + piecestub.oncrafted = oncrafted; + piecestub.use_spawn_num = use_spawn_num; + piecestub.is_shared = is_shared; + piecestub.vox_id = vox_id; + if ( isDefined( client_field_value ) ) + { + if ( isDefined( is_shared ) && is_shared ) + { +/# + assert( isstring( client_field_value ), "Client field value for shared item (" + piecename + ") should be a string (the name of the ClientField to use)" ); +#/ + piecestub.client_field_id = client_field_value; + } + else + { + piecestub.client_field_state = client_field_value; + } + } + return piecestub; +} + +manage_multiple_pieces( max_instances ) +{ + self.max_instances = max_instances; + self.managing_pieces = 1; + self.piece_allocated = []; +} + +combine_craftable_pieces( piece1, piece2, piece3 ) +{ + spawns1 = piece1.spawns; + spawns2 = piece2.spawns; + spawns = arraycombine( spawns1, spawns2, 1, 0 ); + if ( isDefined( piece3 ) ) + { + spawns3 = piece3.spawns; + spawns = arraycombine( spawns, spawns3, 1, 0 ); + spawns = array_randomize( spawns ); + piece3.spawns = spawns; + } + else + { + spawns = array_randomize( spawns ); + } + piece1.spawns = spawns; + piece2.spawns = spawns; +} + +add_craftable_piece( piecestub, tag_name, can_reuse ) +{ + if ( !isDefined( self.a_piecestubs ) ) + { + self.a_piecestubs = []; + } + if ( isDefined( tag_name ) ) + { + piecestub.tag_name = tag_name; + } + if ( isDefined( can_reuse ) ) + { + piecestub.can_reuse = can_reuse; + } + self.a_piecestubs[ self.a_piecestubs.size ] = piecestub; +} + +player_drop_piece_on_downed() +{ + self endon( "craftable_piece_released" ); + self waittill( "bled_out" ); + onplayerlaststand(); +} + +onplayerlaststand() +{ + piece = self.current_craftable_piece; + if ( isDefined( piece ) ) + { + return_to_start_pos = 0; + if ( isDefined( level.safe_place_for_craftable_piece ) ) + { + if ( !( self [[ level.safe_place_for_craftable_piece ]]( piece ) ) ) + { + return_to_start_pos = 1; + } + } + if ( return_to_start_pos ) + { + piece piece_spawn_at(); + } + else + { + piece piece_spawn_at( self.origin + vectorScale( ( 0, 0, 1 ), 5 ), self.angles ); + } + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } + self setclientfieldtoplayer( "craftable", 0 ); + } + self.current_craftable_piece = undefined; + self notify( "craftable_piece_released" ); +} + +piecestub_get_unitrigger_origin() +{ + if ( isDefined( self.origin_parent ) ) + { + return self.origin_parent.origin + vectorScale( ( 0, 0, 1 ), 12 ); + } + return self.origin; +} + +generate_piece_unitrigger( classname, origin, angles, flags, radius, script_height, moving ) +{ + if ( !isDefined( radius ) ) + { + radius = 64; + } + if ( !isDefined( script_height ) ) + { + script_height = 64; + } + script_width = script_height; + if ( !isDefined( script_width ) ) + { + script_width = 64; + } + script_length = script_height; + if ( !isDefined( script_length ) ) + { + script_length = 64; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.origin = origin; + if ( isDefined( script_length ) ) + { + unitrigger_stub.script_length = script_length; + } + else + { + unitrigger_stub.script_length = 13,5; + } + if ( isDefined( script_width ) ) + { + unitrigger_stub.script_width = script_width; + } + else + { + unitrigger_stub.script_width = 27,5; + } + if ( isDefined( script_height ) ) + { + unitrigger_stub.script_height = script_height; + } + else + { + unitrigger_stub.script_height = 24; + } + unitrigger_stub.radius = radius; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + unitrigger_stub.hint_string = &"ZOMBIE_BUILD_PIECE_GRAB"; + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + unitrigger_stub.require_look_at = 0; + switch( classname ) + { + case "trigger_radius": + unitrigger_stub.script_unitrigger_type = "unitrigger_radius"; + break; + case "trigger_radius_use": + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + break; + case "trigger_box": + unitrigger_stub.script_unitrigger_type = "unitrigger_box"; + break; + case "trigger_box_use": + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + break; + } + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + unitrigger_stub.prompt_and_visibility_func = ::piecetrigger_update_prompt; + unitrigger_stub.originfunc = ::piecestub_get_unitrigger_origin; + unitrigger_stub.onspawnfunc = ::anystub_on_spawn_trigger; + if ( isDefined( moving ) && moving ) + { + maps/mp/zombies/_zm_unitrigger::register_unitrigger( unitrigger_stub, ::piece_unitrigger_think ); + } + else + { + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::piece_unitrigger_think ); + } + return unitrigger_stub; +} + +piecetrigger_update_prompt( player ) +{ + can_use = self.stub piecestub_update_prompt( player ); + self setinvisibletoplayer( player, !can_use ); + self sethintstring( self.stub.hint_string ); + return can_use; +} + +piecestub_update_prompt( player ) +{ + if ( !self anystub_update_prompt( player ) ) + { + return 0; + } + if ( isDefined( player.current_craftable_piece ) && isDefined( self.piece.is_shared ) && !self.piece.is_shared ) + { + if ( !level.craftable_piece_swap_allowed ) + { + self.hint_string = &"ZM_CRAFTABLES_PIECE_NO_SWITCH"; + } + else + { + spiece = self.piece; + cpiece = player.current_craftable_piece; + if ( spiece.piecename == cpiece.piecename && spiece.craftablename == cpiece.craftablename ) + { + self.hint_string = ""; + return 0; + } + self.hint_string = &"ZOMBIE_BUILD_PIECE_SWITCH"; + } + } + else + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_GRAB"; + } + return 1; +} + +piece_unitrigger_think() +{ + self endon( "kill_trigger" ); + while ( 1 ) + { + self waittill( "trigger", player ); + while ( player != self.parent_player ) + { + continue; + } + while ( isDefined( player.screecher_weapon ) ) + { + continue; + } + while ( !level.craftable_piece_swap_allowed && isDefined( player.current_craftable_piece ) && isDefined( self.stub.piece.is_shared ) && !self.stub.piece.is_shared ) + { + continue; + } + while ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + status = player player_can_take_piece( self.stub.piece ); + if ( !status ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + continue; + } + else + { + player thread player_take_piece( self.stub.piece ); + } + } +} + +player_can_take_piece( piece ) +{ + if ( !isDefined( piece ) ) + { + return 0; + } + return 1; +} + +dbline( from, to ) +{ +/# + time = 20; + while ( time > 0 ) + { + line( from, to, ( 0, 0, 1 ), 0, 1 ); + time -= 0,05; + wait 0,05; +#/ + } +} + +player_throw_piece( piece, origin, dir, return_to_spawn, return_time, endangles ) +{ +/# + assert( isDefined( piece ) ); +#/ + if ( isDefined( piece ) ) + { +/# + thread dbline( origin, origin + dir ); +#/ + pass = 0; + done = 0; + altmodel = undefined; + while ( pass < 2 && !done ) + { + grenade = self magicgrenadetype( "buildable_piece_zm", origin, dir, 30000 ); + grenade thread watch_hit_players(); + grenade ghost(); + if ( !isDefined( altmodel ) ) + { + altmodel = spawn( "script_model", grenade.origin ); + altmodel setmodel( piece.modelname ); + } + altmodel.origin = grenade.angles; + altmodel.angles = grenade.angles; + altmodel linkto( grenade, "", ( 0, 0, 1 ), ( 0, 0, 1 ) ); + grenade.altmodel = altmodel; + grenade waittill( "stationary" ); + grenade_origin = grenade.origin; + grenade_angles = grenade.angles; + landed_on = grenade getgroundent(); + grenade delete(); + if ( isDefined( landed_on ) && landed_on == level ) + { + done = 1; + continue; + } + else + { + origin = grenade_origin; + dir = ( ( dir[ 0 ] * -1 ) / 10, ( dir[ 1 ] * -1 ) / 10, -1 ); + pass++; + } + } + if ( !isDefined( endangles ) ) + { + endangles = grenade_angles; + } + piece piece_spawn_at( grenade_origin, endangles ); + if ( isDefined( altmodel ) ) + { + altmodel delete(); + } + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } + if ( isDefined( return_to_spawn ) && return_to_spawn ) + { + piece piece_wait_and_return( return_time ); + } + } +} + +watch_hit_players() +{ + self endon( "death" ); + self endon( "stationary" ); + while ( isDefined( self ) ) + { + self waittill( "grenade_bounce", pos, normal, ent ); + if ( isplayer( ent ) ) + { + ent explosiondamage( 25, pos ); + } + } +} + +piece_wait_and_return( return_time ) +{ + self endon( "pickup" ); + wait 0,15; + if ( isDefined( level.exploding_jetgun_fx ) ) + { + playfxontag( level.exploding_jetgun_fx, self.model, "tag_origin" ); + } + else + { + playfxontag( level._effect[ "powerup_on" ], self.model, "tag_origin" ); + } + wait ( return_time - 6 ); + self piece_hide(); + wait 1; + self piece_show(); + wait 1; + self piece_hide(); + wait 1; + self piece_show(); + wait 1; + self piece_hide(); + wait 1; + self piece_show(); + wait 1; + self notify( "respawn" ); + self piece_unspawn(); + self piece_spawn_at(); +} + +player_return_piece_to_original_spawn() +{ + self notify( "craftable_piece_released" ); + piece = self.current_craftable_piece; + self.current_craftable_piece = undefined; + if ( isDefined( piece ) ) + { + piece piece_spawn_at(); + self setclientfieldtoplayer( "craftable", 0 ); + } +} + +player_drop_piece_on_death() +{ + self notify( "craftable_piece_released" ); + self endon( "craftable_piece_released" ); + self thread player_drop_piece_on_downed(); + origin = self.origin; + angles = self.angles; + piece = self.current_craftable_piece; + self waittill( "disconnect" ); + piece piece_spawn_at( origin, angles ); + if ( isDefined( self ) ) + { + self setclientfieldtoplayer( "craftable", 0 ); + } +} + +player_drop_piece( piece ) +{ + if ( !isDefined( piece ) ) + { + piece = self.current_craftable_piece; + } + if ( isDefined( piece ) ) + { + piece.damage = 0; + piece piece_spawn_at( self.origin, self.angles ); + self setclientfieldtoplayer( "craftable", 0 ); + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } + } + self.current_craftable_piece = undefined; + self notify( "craftable_piece_released" ); +} + +player_take_piece( piecespawn ) +{ + piecestub = piecespawn.piecestub; + damage = piecespawn.damage; + if ( isDefined( piecestub.is_shared ) && !piecestub.is_shared && isDefined( self.current_craftable_piece ) ) + { + other_piece = self.current_craftable_piece; + self player_drop_piece( self.current_craftable_piece ); + other_piece.damage = damage; + self do_player_general_vox( "general", "craft_swap" ); + } + if ( isDefined( piecestub.onpickup ) ) + { + piecespawn [[ piecestub.onpickup ]]( self ); + } + if ( isDefined( piecestub.is_shared ) && piecestub.is_shared ) + { + if ( isDefined( piecestub.client_field_id ) ) + { + level setclientfield( piecestub.client_field_id, 1 ); + } + } + else + { + if ( isDefined( piecestub.client_field_state ) ) + { + self setclientfieldtoplayer( "craftable", piecestub.client_field_state ); + } + } + piecespawn piece_unspawn(); + piecespawn notify( "pickup" ); + if ( isDefined( piecestub.is_shared ) && piecestub.is_shared ) + { + piecespawn.in_shared_inventory = 1; + } + else + { + self.current_craftable_piece = piecespawn; + self thread player_drop_piece_on_death(); + } + self track_craftable_piece_pickedup( piecespawn ); +} + +player_destroy_piece( piece ) +{ + if ( !isDefined( piece ) ) + { + piece = self.current_craftable_piece; + } + if ( isDefined( piece ) ) + { + self setclientfieldtoplayer( "craftable", 0 ); + } + self.current_craftable_piece = undefined; + self notify( "craftable_piece_released" ); +} + +claim_location( location ) +{ + if ( !isDefined( level.craftable_claimed_locations ) ) + { + level.craftable_claimed_locations = []; + } + if ( !isDefined( level.craftable_claimed_locations[ location ] ) ) + { + level.craftable_claimed_locations[ location ] = 1; + return 1; + } + return 0; +} + +is_point_in_craft_trigger( point ) +{ + candidate_list = []; + _a952 = level.zones; + _k952 = getFirstArrayKey( _a952 ); + while ( isDefined( _k952 ) ) + { + zone = _a952[ _k952 ]; + if ( isDefined( zone.unitrigger_stubs ) ) + { + candidate_list = arraycombine( candidate_list, zone.unitrigger_stubs, 1, 0 ); + } + _k952 = getNextArrayKey( _a952, _k952 ); + } + valid_range = 128; + closest = maps/mp/zombies/_zm_unitrigger::get_closest_unitriggers( point, candidate_list, valid_range ); + index = 0; + while ( index < closest.size ) + { + if ( isDefined( closest[ index ].registered ) && closest[ index ].registered && isDefined( closest[ index ].piece ) ) + { + return 1; + } + index++; + } + return 0; +} + +piece_allocate_spawn( piecestub ) +{ + self.current_spawn = 0; + self.managed_spawn = 1; + self.piecestub = piecestub; + if ( self.spawns.size >= 1 && self.spawns.size > 1 ) + { + any_good = 0; + any_okay = 0; + totalweight = 0; + spawnweights = []; + i = 0; + while ( i < self.spawns.size ) + { + if ( isDefined( piecestub.piece_allocated[ i ] ) && piecestub.piece_allocated[ i ] ) + { + spawnweights[ i ] = 0; + } + else + { + if ( is_point_in_craft_trigger( self.spawns[ i ].origin ) ) + { + any_okay = 1; + spawnweights[ i ] = 0,01; + break; + } + else + { + any_good = 1; + spawnweights[ i ] = 1; + } + } + totalweight += spawnweights[ i ]; + i++; + } +/# + if ( !any_good ) + { + assert( any_okay, "There is nowhere to spawn this piece" ); + } +#/ + if ( any_good ) + { + totalweight = float( int( totalweight ) ); + } + r = randomfloat( totalweight ); + i = 0; + while ( i < self.spawns.size ) + { + if ( !any_good || spawnweights[ i ] >= 1 ) + { + r -= spawnweights[ i ]; + if ( r < 0 ) + { + self.current_spawn = i; + piecestub.piece_allocated[ self.current_spawn ] = 1; + return; + } + } + i++; + } + self.current_spawn = randomint( self.spawns.size ); + piecestub.piece_allocated[ self.current_spawn ] = 1; + } +} + +piece_deallocate_spawn() +{ + if ( isDefined( self.current_spawn ) ) + { + self.piecestub.piece_allocated[ self.current_spawn ] = 0; + self.current_spawn = undefined; + } + self.start_origin = undefined; +} + +piece_pick_random_spawn() +{ + self.current_spawn = 0; + while ( self.spawns.size >= 1 && self.spawns.size > 1 ) + { + self.current_spawn = randomint( self.spawns.size ); + while ( isDefined( self.spawns[ self.current_spawn ].claim_location ) && !claim_location( self.spawns[ self.current_spawn ].claim_location ) ) + { + arrayremoveindex( self.spawns, self.current_spawn ); + if ( self.spawns.size < 1 ) + { + self.current_spawn = 0; +/# + println( "ERROR: All craftable spawn locations claimed" ); +#/ + return; + } + self.current_spawn = randomint( self.spawns.size ); + } + } +} + +piece_set_spawn( num ) +{ + self.current_spawn = 0; + if ( self.spawns.size >= 1 && self.spawns.size > 1 ) + { + self.current_spawn = int( min( num, self.spawns.size - 1 ) ); + } +} + +piece_spawn_in( piecestub ) +{ + if ( self.spawns.size < 1 ) + { + return; + } + if ( isDefined( self.managed_spawn ) && self.managed_spawn ) + { + if ( !isDefined( self.current_spawn ) ) + { + self piece_allocate_spawn( self.piecestub ); + } + } + if ( !isDefined( self.current_spawn ) ) + { + self.current_spawn = 0; + } + spawndef = self.spawns[ self.current_spawn ]; + self.unitrigger = generate_piece_unitrigger( "trigger_radius_use", spawndef.origin + vectorScale( ( 0, 0, 1 ), 12 ), spawndef.angles, 0, piecestub.radius, piecestub.height, 0 ); + self.unitrigger.piece = self; + self.radius = piecestub.radius; + self.height = piecestub.height; + self.craftablename = piecestub.craftablename; + self.piecename = piecestub.piecename; + self.modelname = piecestub.modelname; + self.hud_icon = piecestub.hud_icon; + self.tag_name = piecestub.tag_name; + self.drop_offset = piecestub.drop_offset; + self.start_origin = spawndef.origin; + self.start_angles = spawndef.angles; + self.client_field_state = piecestub.client_field_state; + self.is_shared = piecestub.is_shared; + self.model = spawn( "script_model", self.start_origin ); + if ( isDefined( self.start_angles ) ) + { + self.model.angles = self.start_angles; + } + self.model setmodel( piecestub.modelname ); + if ( isDefined( piecestub.onspawn ) ) + { + self [[ piecestub.onspawn ]](); + } + self.model ghostindemo(); + self.model.hud_icon = piecestub.hud_icon; + self.piecestub = piecestub; + self.unitrigger.origin_parent = self.model; +} + +piece_spawn_at( origin, angles, use_random_start ) +{ + if ( self.spawns.size < 1 ) + { + return; + } + if ( isDefined( self.managed_spawn ) && self.managed_spawn ) + { + if ( !isDefined( self.current_spawn ) && !isDefined( origin ) ) + { + self piece_allocate_spawn( self.piecestub ); + spawndef = self.spawns[ self.current_spawn ]; + self.start_origin = spawndef.origin; + self.start_angles = spawndef.angles; + } + } + else + { + if ( !isDefined( self.current_spawn ) ) + { + self.current_spawn = 0; + } + } + unitrigger_offset = vectorScale( ( 0, 0, 1 ), 12 ); + if ( isDefined( use_random_start ) && use_random_start ) + { + self piece_pick_random_spawn(); + spawndef = self.spawns[ self.current_spawn ]; + self.start_origin = spawndef.origin; + self.start_angles = spawndef.angles; + origin = spawndef.origin; + angles = spawndef.angles; + } + else + { + if ( !isDefined( origin ) ) + { + origin = self.start_origin; + } + else + { + origin += ( 0, 0, self.drop_offset ); + unitrigger_offset -= ( 0, 0, self.drop_offset ); + } + if ( !isDefined( angles ) ) + { + angles = self.start_angles; + } +/# + if ( !isDefined( level.drop_offset ) ) + { + level.drop_offset = 0; + } + origin += ( 0, 0, level.drop_offset ); + unitrigger_offset -= ( 0, 0, level.drop_offset ); +#/ + } + self.model = spawn( "script_model", origin ); + if ( isDefined( angles ) ) + { + self.model.angles = angles; + } + self.model setmodel( self.modelname ); + if ( isDefined( level.equipment_safe_to_drop ) ) + { + if ( !( [[ level.equipment_safe_to_drop ]]( self.model ) ) ) + { + origin = self.start_origin; + angles = self.start_angles; + self.model.origin = origin; + self.model.angles = angles; + } + } + if ( isDefined( self.onspawn ) ) + { + self [[ self.onspawn ]](); + } + if ( isDefined( self.model.canmove ) ) + { + self.unitrigger = generate_piece_unitrigger( "trigger_radius_use", origin + unitrigger_offset, angles, 0, self.radius, self.height, self.model.canmove ); + } + self.unitrigger.piece = self; + self.model.hud_icon = self.hud_icon; + self.unitrigger.origin_parent = self.model; +} + +piece_unspawn() +{ + if ( isDefined( self.managed_spawn ) && self.managed_spawn ) + { + self piece_deallocate_spawn(); + } + if ( isDefined( self.model ) ) + { + self.model delete(); + } + self.model = undefined; + if ( isDefined( self.unitrigger ) ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.unitrigger ); + } + self.unitrigger = undefined; +} + +piece_hide() +{ + if ( isDefined( self.model ) ) + { + self.model ghost(); + } +} + +piece_show() +{ + if ( isDefined( self.model ) ) + { + self.model show(); + } +} + +generate_piece( piecestub ) +{ + piecespawn = spawnstruct(); + piecespawn.spawns = piecestub.spawns; + if ( isDefined( piecestub.managing_pieces ) && piecestub.managing_pieces ) + { + piecespawn piece_allocate_spawn( piecestub ); + } + else + { + if ( isDefined( piecestub.use_spawn_num ) ) + { + piecespawn piece_set_spawn( piecestub.use_spawn_num ); + } + else + { + piecespawn piece_pick_random_spawn(); + } + } + piecespawn piece_spawn_in( piecestub ); + if ( piecespawn.spawns.size >= 1 ) + { + piecespawn.hud_icon = piecestub.hud_icon; + } + if ( isDefined( piecestub.onpickup ) ) + { + piecespawn.onpickup = piecestub.onpickup; + } + else + { + piecespawn.onpickup = ::onpickuputs; + } + if ( isDefined( piecestub.ondrop ) ) + { + piecespawn.ondrop = piecestub.ondrop; + } + else + { + piecespawn.ondrop = ::ondroputs; + } + if ( isDefined( piecestub.oncrafted ) ) + { + piecespawn.oncrafted = piecestub.oncrafted; + } + return piecespawn; +} + +craftable_piece_unitriggers( craftable_name, origin ) +{ +/# + assert( isDefined( craftable_name ) ); +#/ +/# + assert( isDefined( level.zombie_craftablestubs[ craftable_name ] ), "Called craftable_think() without including the craftable - " + craftable_name ); +#/ + craftable = level.zombie_craftablestubs[ craftable_name ]; + if ( !isDefined( craftable.a_piecestubs ) ) + { + craftable.a_piecestubs = []; + } + flag_wait( "start_zombie_round_logic" ); + craftablespawn = spawnstruct(); + craftablespawn.craftable_name = craftable_name; + if ( !isDefined( craftablespawn.a_piecespawns ) ) + { + craftablespawn.a_piecespawns = []; + } + craftablepickups = []; + _a1314 = craftable.a_piecestubs; + _k1314 = getFirstArrayKey( _a1314 ); + while ( isDefined( _k1314 ) ) + { + piecestub = _a1314[ _k1314 ]; + if ( !isDefined( piecestub.generated_instances ) ) + { + piecestub.generated_instances = 0; + } + if ( isDefined( piecestub.piecespawn ) && isDefined( piecestub.can_reuse ) && piecestub.can_reuse ) + { + piece = piecestub.piecespawn; + } + else + { + if ( piecestub.generated_instances >= piecestub.max_instances ) + { + piece = piecestub.piecespawn; + break; + } + else + { + piece = generate_piece( piecestub ); + piecestub.piecespawn = piece; + piecestub.generated_instances++; + } + } + craftablespawn.a_piecespawns[ craftablespawn.a_piecespawns.size ] = piece; + _k1314 = getNextArrayKey( _a1314, _k1314 ); + } + craftablespawn.stub = self; + return craftablespawn; +} + +hide_craftable_table_model( trigger_targetname ) +{ + trig = getent( trigger_targetname, "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + if ( isDefined( trig.target ) ) + { + model = getent( trig.target, "targetname" ); + if ( isDefined( model ) ) + { + model ghost(); + model notsolid(); + } + } +} + +setup_unitrigger_craftable( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + trig = getent( trigger_targetname, "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + return setup_unitrigger_craftable_internal( trig, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +setup_unitrigger_craftable_array( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + triggers = getentarray( trigger_targetname, "targetname" ); + stubs = []; + _a1376 = triggers; + _k1376 = getFirstArrayKey( _a1376 ); + while ( isDefined( _k1376 ) ) + { + trig = _a1376[ _k1376 ]; + stubs[ stubs.size ] = setup_unitrigger_craftable_internal( trig, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); + _k1376 = getNextArrayKey( _a1376, _k1376 ); + } + return stubs; +} + +setup_unitrigger_craftable_internal( trig, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + if ( !isDefined( trig ) ) + { + return; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.craftablestub = level.zombie_include_craftables[ equipname ]; + angles = trig.script_angles; + if ( !isDefined( angles ) ) + { + angles = ( 0, 0, 1 ); + } + unitrigger_stub.origin = trig.origin + ( anglesToRight( angles ) * -6 ); + unitrigger_stub.angles = trig.angles; + if ( isDefined( trig.script_angles ) ) + { + unitrigger_stub.angles = trig.script_angles; + } + unitrigger_stub.equipname = equipname; + unitrigger_stub.weaponname = weaponname; + unitrigger_stub.trigger_hintstring = trigger_hintstring; + unitrigger_stub.delete_trigger = delete_trigger; + unitrigger_stub.crafted = 0; + unitrigger_stub.persistent = persistent; + unitrigger_stub.usetime = int( 3000 ); + unitrigger_stub.onbeginuse = ::onbeginuseuts; + unitrigger_stub.onenduse = ::onenduseuts; + unitrigger_stub.onuse = ::onuseplantobjectuts; + unitrigger_stub.oncantuse = ::oncantuseuts; + if ( isDefined( trig.script_length ) ) + { + unitrigger_stub.script_length = trig.script_length; + } + else + { + unitrigger_stub.script_length = 32; + } + if ( isDefined( trig.script_width ) ) + { + unitrigger_stub.script_width = trig.script_width; + } + else + { + unitrigger_stub.script_width = 100; + } + if ( isDefined( trig.script_height ) ) + { + unitrigger_stub.script_height = trig.script_height; + } + else + { + unitrigger_stub.script_height = 64; + } + unitrigger_stub.target = trig.target; + unitrigger_stub.targetname = trig.targetname; + unitrigger_stub.script_noteworthy = trig.script_noteworthy; + unitrigger_stub.script_parameters = trig.script_parameters; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + if ( isDefined( level.zombie_craftablestubs[ equipname ].str_to_craft ) ) + { + unitrigger_stub.hint_string = level.zombie_craftablestubs[ equipname ].str_to_craft; + } + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + unitrigger_stub.require_look_at = 1; + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + if ( isDefined( unitrigger_stub.craftablestub.custom_craftablestub_update_prompt ) ) + { + unitrigger_stub.custom_craftablestub_update_prompt = unitrigger_stub.craftablestub.custom_craftablestub_update_prompt; + } + unitrigger_stub.prompt_and_visibility_func = ::craftabletrigger_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::craftable_place_think ); + unitrigger_stub.piece_trigger = trig; + trig.trigger_stub = unitrigger_stub; + unitrigger_stub.zombie_weapon_upgrade = trig.zombie_weapon_upgrade; + if ( isDefined( unitrigger_stub.target ) ) + { + unitrigger_stub.model = getent( unitrigger_stub.target, "targetname" ); + if ( isDefined( unitrigger_stub.model ) ) + { + if ( isDefined( unitrigger_stub.zombie_weapon_upgrade ) ) + { + unitrigger_stub.model useweaponhidetags( unitrigger_stub.zombie_weapon_upgrade ); + } + unitrigger_stub.model ghost(); + unitrigger_stub.model notsolid(); + } + } + if ( unitrigger_stub.equipname == "open_table" ) + { + unitrigger_stub.a_uts_open_craftables_available = []; + unitrigger_stub.n_open_craftable_choice = -1; + unitrigger_stub.b_open_craftable_checking_input = 0; + } + unitrigger_stub.craftablespawn = unitrigger_stub craftable_piece_unitriggers( equipname, unitrigger_stub.origin ); + if ( delete_trigger ) + { + trig delete(); + } + level.a_uts_craftables[ level.a_uts_craftables.size ] = unitrigger_stub; + return unitrigger_stub; +} + +setup_craftable_pieces() +{ + unitrigger_stub = spawnstruct(); + unitrigger_stub.craftablestub = level.zombie_include_craftables[ self.name ]; + unitrigger_stub.equipname = self.name; + unitrigger_stub.craftablespawn = unitrigger_stub craftable_piece_unitriggers( self.name, unitrigger_stub.origin ); + level.a_uts_craftables[ level.a_uts_craftables.size ] = unitrigger_stub; + return unitrigger_stub; +} + +craftable_has_piece( piece ) +{ + i = 0; + while ( i < self.a_piecespawns.size ) + { + if ( self.a_piecespawns[ i ].piecename == piece.piecename && self.a_piecespawns[ i ].craftablename == piece.craftablename ) + { + return 1; + } + i++; + } + return 0; +} + +get_actual_uts_craftable() +{ + if ( self.craftable_name == "open_table" && self.n_open_craftable_choice != -1 ) + { + return self.stub.a_uts_open_craftables_available[ self.n_open_craftable_choice ]; + } + else + { + return self.stub; + } +} + +get_actual_craftablespawn() +{ + if ( self.craftable_name == "open_table" && self.stub.n_open_craftable_choice != -1 && isDefined( self.stub.a_uts_open_craftables_available[ self.stub.n_open_craftable_choice ].craftablespawn ) ) + { + return self.stub.a_uts_open_craftables_available[ self.stub.n_open_craftable_choice ].craftablespawn; + } + else + { + return self; + } +} + +craftable_can_use_shared_piece() +{ + uts_craftable = self.stub; + if ( isDefined( uts_craftable.n_open_craftable_choice ) && uts_craftable.n_open_craftable_choice != -1 && isDefined( uts_craftable.a_uts_open_craftables_available[ uts_craftable.n_open_craftable_choice ] ) ) + { + return 1; + } + if ( isDefined( uts_craftable.craftablestub.need_all_pieces ) && uts_craftable.craftablestub.need_all_pieces ) + { + _a1595 = self.a_piecespawns; + _k1595 = getFirstArrayKey( _a1595 ); + while ( isDefined( _k1595 ) ) + { + piece = _a1595[ _k1595 ]; + if ( isDefined( piece.in_shared_inventory ) && !piece.in_shared_inventory ) + { + return 0; + } + _k1595 = getNextArrayKey( _a1595, _k1595 ); + } + return 1; + } + else + { + _a1608 = self.a_piecespawns; + _k1608 = getFirstArrayKey( _a1608 ); + while ( isDefined( _k1608 ) ) + { + piece = _a1608[ _k1608 ]; + if ( isDefined( piece.crafted ) && !piece.crafted && isDefined( piece.in_shared_inventory ) && piece.in_shared_inventory ) + { + return 1; + } + _k1608 = getNextArrayKey( _a1608, _k1608 ); + } + } + return 0; +} + +craftable_set_piece_crafted( piecespawn_check, player ) +{ + craftablespawn_check = get_actual_craftablespawn(); + _a1625 = craftablespawn_check.a_piecespawns; + _k1625 = getFirstArrayKey( _a1625 ); + while ( isDefined( _k1625 ) ) + { + piecespawn = _a1625[ _k1625 ]; + if ( isDefined( piecespawn_check ) ) + { + if ( piecespawn.piecename == piecespawn_check.piecename && piecespawn.craftablename == piecespawn_check.craftablename ) + { + piecespawn.crafted = 1; + if ( isDefined( piecespawn.oncrafted ) ) + { + piecespawn thread [[ piecespawn.oncrafted ]]( player ); + } + } + } + else + { + if ( isDefined( piecespawn.is_shared ) && piecespawn.is_shared && isDefined( piecespawn.in_shared_inventory ) && piecespawn.in_shared_inventory ) + { + piecespawn.crafted = 1; + if ( isDefined( piecespawn.oncrafted ) ) + { + piecespawn thread [[ piecespawn.oncrafted ]]( player ); + } + piecespawn.in_shared_inventory = 0; + } + } + _k1625 = getNextArrayKey( _a1625, _k1625 ); + } +} + +craftable_set_piece_crafting( piecespawn_check ) +{ + craftablespawn_check = get_actual_craftablespawn(); + _a1664 = craftablespawn_check.a_piecespawns; + _k1664 = getFirstArrayKey( _a1664 ); + while ( isDefined( _k1664 ) ) + { + piecespawn = _a1664[ _k1664 ]; + if ( isDefined( piecespawn_check ) ) + { + if ( piecespawn.piecename == piecespawn_check.piecename && piecespawn.craftablename == piecespawn_check.craftablename ) + { + piecespawn.crafting = 1; + } + } + if ( isDefined( piecespawn.is_shared ) && piecespawn.is_shared && isDefined( piecespawn.in_shared_inventory ) && piecespawn.in_shared_inventory ) + { + piecespawn.crafting = 1; + } + _k1664 = getNextArrayKey( _a1664, _k1664 ); + } +} + +craftable_clear_piece_crafting( piecespawn_check ) +{ + if ( isDefined( piecespawn_check ) ) + { + piecespawn_check.crafting = 0; + } + craftablespawn_check = get_actual_craftablespawn(); + _a1693 = craftablespawn_check.a_piecespawns; + _k1693 = getFirstArrayKey( _a1693 ); + while ( isDefined( _k1693 ) ) + { + piecespawn = _a1693[ _k1693 ]; + if ( isDefined( piecespawn.is_shared ) && piecespawn.is_shared && isDefined( piecespawn.in_shared_inventory ) && piecespawn.in_shared_inventory ) + { + piecespawn.crafting = 0; + } + _k1693 = getNextArrayKey( _a1693, _k1693 ); + } +} + +craftable_is_piece_crafted( piece ) +{ + i = 0; + while ( i < self.a_piecespawns.size ) + { + if ( self.a_piecespawns[ i ].piecename == piece.piecename && self.a_piecespawns[ i ].craftablename == piece.craftablename ) + { + if ( isDefined( self.a_piecespawns[ i ].crafted ) ) + { + return self.a_piecespawns[ i ].crafted; + } + } + i++; + } + return 0; +} + +craftable_is_piece_crafting( piecespawn_check ) +{ + craftablespawn_check = get_actual_craftablespawn(); + _a1720 = craftablespawn_check.a_piecespawns; + _k1720 = getFirstArrayKey( _a1720 ); + while ( isDefined( _k1720 ) ) + { + piecespawn = _a1720[ _k1720 ]; + if ( isDefined( piecespawn_check ) ) + { + if ( piecespawn.piecename == piecespawn_check.piecename && piecespawn.craftablename == piecespawn_check.craftablename ) + { + return piecespawn.crafting; + } + } + if ( isDefined( piecespawn.is_shared ) && piecespawn.is_shared && isDefined( piecespawn.in_shared_inventory ) && piecespawn.in_shared_inventory && isDefined( piecespawn.crafting ) && piecespawn.crafting ) + { + return 1; + } + _k1720 = getNextArrayKey( _a1720, _k1720 ); + } + return 0; +} + +craftable_is_piece_crafted_or_crafting( piece ) +{ + i = 0; + while ( i < self.a_piecespawns.size ) + { + if ( self.a_piecespawns[ i ].piecename == piece.piecename && self.a_piecespawns[ i ].craftablename == piece.craftablename ) + { + if ( isDefined( self.a_piecespawns[ i ].crafted ) && !self.a_piecespawns[ i ].crafted ) + { + if ( isDefined( self.a_piecespawns[ i ].crafting ) ) + { + return self.a_piecespawns[ i ].crafting; + } + } + } + i++; + } + return 0; +} + +craftable_all_crafted() +{ + i = 0; + while ( i < self.a_piecespawns.size ) + { + if ( isDefined( self.a_piecespawns[ i ].crafted ) && !self.a_piecespawns[ i ].crafted ) + { + return 0; + } + i++; + } + return 1; +} + +waittill_crafted( craftable_name ) +{ + level waittill( craftable_name + "_crafted", player ); + return player; +} + +player_can_craft( craftablespawn, continuing ) +{ + if ( !isDefined( craftablespawn ) ) + { + return 0; + } + if ( !craftablespawn craftable_can_use_shared_piece() ) + { + if ( !isDefined( self.current_craftable_piece ) ) + { + return 0; + } + if ( !craftablespawn craftable_has_piece( self.current_craftable_piece ) ) + { + return 0; + } + if ( isDefined( continuing ) && continuing ) + { + if ( craftablespawn craftable_is_piece_crafted( self.current_craftable_piece ) ) + { + return 0; + } + } + else + { + if ( craftablespawn craftable_is_piece_crafted_or_crafting( self.current_craftable_piece ) ) + { + return 0; + } + } + } + if ( isDefined( craftablespawn.stub ) && isDefined( craftablespawn.stub.custom_craftablestub_update_prompt ) && isDefined( craftablespawn.stub.playertrigger[ 0 ] ) && isDefined( craftablespawn.stub.playertrigger[ 0 ].stub ) && !( craftablespawn.stub.playertrigger[ 0 ].stub [[ craftablespawn.stub.custom_craftablestub_update_prompt ]]( self, 1, craftablespawn.stub.playertrigger[ self getentitynumber() ] ) ) ) + { + return 0; + } + return 1; +} + +craftable_transfer_data() +{ + uts_craftable = self.stub; + if ( uts_craftable.n_open_craftable_choice == -1 || !isDefined( uts_craftable.a_uts_open_craftables_available[ uts_craftable.n_open_craftable_choice ] ) ) + { + return; + } + uts_source = uts_craftable.a_uts_open_craftables_available[ uts_craftable.n_open_craftable_choice ]; + uts_target = uts_craftable; + uts_target.craftablestub = uts_source.craftablestub; + uts_target.craftablespawn = uts_source.craftablespawn; + uts_target.crafted = uts_source.crafted; + uts_target.cursor_hint = uts_source.cursor_hint; + uts_target.custom_craftable_update_prompt = uts_source.custom_craftable_update_prompt; + uts_target.equipname = uts_source.equipname; + uts_target.hint_string = uts_source.hint_string; + uts_target.persistent = uts_source.persistent; + uts_target.prompt_and_visibility_func = uts_source.prompt_and_visibility_func; + uts_target.trigger_func = uts_source.trigger_func; + uts_target.trigger_hintstring = uts_source.trigger_hintstring; + uts_target.weaponname = uts_source.weaponname; + uts_target.craftablespawn.stub = uts_target; + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( uts_source ); + uts_source craftablestub_remove(); + return uts_target; +} + +player_craft( craftablespawn ) +{ + craftablespawn craftable_set_piece_crafted( self.current_craftable_piece, self ); + if ( isDefined( self.current_craftable_piece ) && isDefined( self.current_craftable_piece.crafted ) && self.current_craftable_piece.crafted ) + { + player_destroy_piece( self.current_craftable_piece ); + } + if ( isDefined( craftablespawn.stub.n_open_craftable_choice ) ) + { + uts_craftable = craftablespawn craftable_transfer_data(); + craftablespawn = uts_craftable.craftablespawn; + update_open_table_status(); + } + else + { + uts_craftable = craftablespawn.stub; + } + if ( !isDefined( uts_craftable.model ) && isDefined( uts_craftable.craftablestub.str_model ) ) + { + craftablestub = uts_craftable.craftablestub; + s_model = getstruct( uts_craftable.target, "targetname" ); + if ( isDefined( s_model ) ) + { + m_spawn = spawn( "script_model", s_model.origin ); + if ( isDefined( craftablestub.v_origin_offset ) ) + { + m_spawn.origin += craftablestub.v_origin_offset; + } + m_spawn.angles = s_model.angles; + if ( isDefined( craftablestub.v_angle_offset ) ) + { + m_spawn.angles += craftablestub.v_angle_offset; + } + m_spawn setmodel( craftablestub.str_model ); + uts_craftable.model = m_spawn; + } + } + while ( isDefined( uts_craftable.model ) ) + { + i = 0; + while ( i < craftablespawn.a_piecespawns.size ) + { + if ( isDefined( craftablespawn.a_piecespawns[ i ].tag_name ) ) + { + uts_craftable.model notsolid(); + if ( isDefined( craftablespawn.a_piecespawns[ i ].crafted ) && !craftablespawn.a_piecespawns[ i ].crafted ) + { + uts_craftable.model hidepart( craftablespawn.a_piecespawns[ i ].tag_name ); + i++; + continue; + } + else + { + uts_craftable.model show(); + uts_craftable.model showpart( craftablespawn.a_piecespawns[ i ].tag_name ); + } + } + i++; + } + } + self track_craftable_pieces_crafted( craftablespawn ); + if ( craftablespawn craftable_all_crafted() ) + { + self player_finish_craftable( craftablespawn ); + self track_craftables_crafted( craftablespawn ); + if ( isDefined( level.craftable_crafted_custom_func ) ) + { + self thread [[ level.craftable_crafted_custom_func ]]( craftablespawn ); + } + self playsound( "zmb_buildable_complete" ); + } + else + { + self playsound( "zmb_buildable_piece_add" ); +/# + assert( isDefined( level.zombie_craftablestubs[ craftablespawn.craftable_name ].str_crafting ), "Missing builing hint" ); +#/ + if ( isDefined( level.zombie_craftablestubs[ craftablespawn.craftable_name ].str_crafting ) ) + { + return level.zombie_craftablestubs[ craftablespawn.craftable_name ].str_crafting; + } + } + return ""; +} + +update_open_table_status() +{ + b_open_craftables_remaining = 0; + _a1963 = level.a_uts_craftables; + _k1963 = getFirstArrayKey( _a1963 ); + while ( isDefined( _k1963 ) ) + { + uts_craftable = _a1963[ _k1963 ]; + if ( isDefined( level.zombie_include_craftables[ uts_craftable.equipname ] ) && isDefined( level.zombie_include_craftables[ uts_craftable.equipname ].is_open_table ) && level.zombie_include_craftables[ uts_craftable.equipname ].is_open_table ) + { + b_piece_crafted = 0; + _a1970 = uts_craftable.craftablespawn.a_piecespawns; + _k1970 = getFirstArrayKey( _a1970 ); + while ( isDefined( _k1970 ) ) + { + piecespawn = _a1970[ _k1970 ]; + if ( isDefined( piecespawn.crafted ) && piecespawn.crafted ) + { + b_piece_crafted = 1; + break; + } + else + { + _k1970 = getNextArrayKey( _a1970, _k1970 ); + } + } + if ( !b_piece_crafted ) + { + b_open_craftables_remaining = 1; + } + } + _k1963 = getNextArrayKey( _a1963, _k1963 ); + } + while ( !b_open_craftables_remaining ) + { + _a1989 = level.a_uts_craftables; + _k1989 = getFirstArrayKey( _a1989 ); + while ( isDefined( _k1989 ) ) + { + uts_craftable = _a1989[ _k1989 ]; + if ( uts_craftable.equipname == "open_table" ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( uts_craftable ); + } + _k1989 = getNextArrayKey( _a1989, _k1989 ); + } + } +} + +player_finish_craftable( craftablespawn ) +{ + craftablespawn.crafted = 1; + craftablespawn.stub.crafted = 1; + craftablespawn notify( "crafted" ); + level.craftables_crafted[ craftablespawn.craftable_name ] = 1; + level notify( craftablespawn.craftable_name + "_crafted" ); +} + +complete_craftable( str_craftable_name ) +{ + _a2014 = level.a_uts_craftables; + _k2014 = getFirstArrayKey( _a2014 ); + while ( isDefined( _k2014 ) ) + { + uts_craftable = _a2014[ _k2014 ]; + if ( uts_craftable.craftablestub.name == str_craftable_name ) + { + player = getplayers()[ 0 ]; + player player_finish_craftable( uts_craftable.craftablespawn ); + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( uts_craftable ); + if ( isDefined( uts_craftable.craftablestub.onfullycrafted ) ) + { + uts_craftable [[ uts_craftable.craftablestub.onfullycrafted ]](); + } + return; + } + _k2014 = getNextArrayKey( _a2014, _k2014 ); + } +} + +craftablestub_remove() +{ + arrayremovevalue( level.a_uts_craftables, self ); +} + +craftabletrigger_update_prompt( player ) +{ + can_use = self.stub craftablestub_update_prompt( player ); + self sethintstring( self.stub.hint_string ); + return can_use; +} + +craftablestub_update_prompt( player, unitrigger ) +{ + if ( !self anystub_update_prompt( player ) ) + { + return 0; + } + if ( isDefined( self.is_locked ) && self.is_locked ) + { + return 1; + } + can_use = 1; + if ( isDefined( self.custom_craftablestub_update_prompt ) && !( self [[ self.custom_craftablestub_update_prompt ]]( player ) ) ) + { + return 0; + } + if ( isDefined( self.crafted ) && !self.crafted ) + { + if ( !self.craftablespawn craftable_can_use_shared_piece() ) + { + if ( !isDefined( player.current_craftable_piece ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_MORE"; + return 0; + } + else + { + if ( !self.craftablespawn craftable_has_piece( player.current_craftable_piece ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_WRONG"; + return 0; + } + } + } +/# + assert( isDefined( level.zombie_craftablestubs[ self.equipname ].str_to_craft ), "Missing craftable hint" ); +#/ + self.hint_string = level.zombie_craftablestubs[ self.equipname ].str_to_craft; + } + else + { + if ( self.persistent == 1 ) + { + if ( maps/mp/zombies/_zm_equipment::is_limited_equipment( self.weaponname ) && maps/mp/zombies/_zm_equipment::limited_equipment_in_use( self.weaponname ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_ONLY_ONE"; + return 0; + } + if ( player has_player_equipment( self.weaponname ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_HAVE_ONE"; + return 0; + } + self.hint_string = self.trigger_hintstring; + } + else if ( self.persistent == 2 ) + { + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.weaponname, undefined ) ) + { + self.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + return 0; + } + else + { + if ( isDefined( self.str_taken ) && self.str_taken ) + { + self.hint_string = &"ZOMBIE_GO_TO_THE_BOX"; + return 0; + } + } + self.hint_string = self.trigger_hintstring; + } + else + { + self.hint_string = ""; + return 0; + } + } + return 1; +} + +choose_open_craftable( player ) +{ + self endon( "kill_choose_open_craftable" ); + n_playernum = player getentitynumber(); + self.b_open_craftable_checking_input = 1; + b_got_input = 1; + hinttexthudelem = newclienthudelem( player ); + hinttexthudelem.alignx = "center"; + hinttexthudelem.aligny = "middle"; + hinttexthudelem.horzalign = "center"; + hinttexthudelem.vertalign = "bottom"; + hinttexthudelem.y = -100; + if ( player issplitscreen() ) + { + hinttexthudelem.y = -50; + } + hinttexthudelem.foreground = 1; + hinttexthudelem.font = "default"; + hinttexthudelem.fontscale = 1; + hinttexthudelem.alpha = 1; + hinttexthudelem.color = ( 0, 0, 1 ); + hinttexthudelem settext( &"ZM_CRAFTABLES_CHANGE_BUILD" ); + if ( !isDefined( self.opencraftablehudelem ) ) + { + self.opencraftablehudelem = []; + } + self.opencraftablehudelem[ n_playernum ] = hinttexthudelem; + while ( isDefined( self.playertrigger[ n_playernum ] ) && !self.crafted ) + { + if ( player actionslotonebuttonpressed() ) + { + self.n_open_craftable_choice++; + b_got_input = 1; + } + else + { + if ( player actionslottwobuttonpressed() ) + { + self.n_open_craftable_choice--; + + b_got_input = 1; + } + } + if ( self.n_open_craftable_choice >= self.a_uts_open_craftables_available.size ) + { + self.n_open_craftable_choice = 0; + } + else + { + if ( self.n_open_craftable_choice < 0 ) + { + self.n_open_craftable_choice = self.a_uts_open_craftables_available.size - 1; + } + } + if ( b_got_input ) + { + self.equipname = self.a_uts_open_craftables_available[ self.n_open_craftable_choice ].equipname; + self.hint_string = self.a_uts_open_craftables_available[ self.n_open_craftable_choice ].hint_string; + self.playertrigger[ n_playernum ] sethintstring( self.hint_string ); + b_got_input = 0; + } + if ( player is_player_looking_at( self.playertrigger[ n_playernum ].origin, 0,76 ) ) + { + self.opencraftablehudelem[ n_playernum ].alpha = 1; + } + else + { + self.opencraftablehudelem[ n_playernum ].alpha = 0; + } + wait 0,05; + } + self.b_open_craftable_checking_input = 0; + self.opencraftablehudelem[ n_playernum ] destroy(); +} + +open_craftablestub_update_prompt( player ) +{ + if ( isDefined( self.crafted ) && !self.crafted ) + { + self.a_uts_open_craftables_available = []; + _a2235 = level.a_uts_craftables; + _k2235 = getFirstArrayKey( _a2235 ); + while ( isDefined( _k2235 ) ) + { + uts_craftable = _a2235[ _k2235 ]; + if ( isDefined( uts_craftable.craftablestub.is_open_table ) && uts_craftable.craftablestub.is_open_table && isDefined( uts_craftable.crafted ) && !uts_craftable.crafted && uts_craftable.craftablespawn.craftable_name != "open_table" && uts_craftable.craftablespawn craftable_can_use_shared_piece() ) + { + self.a_uts_open_craftables_available[ self.a_uts_open_craftables_available.size ] = uts_craftable; + } + _k2235 = getNextArrayKey( _a2235, _k2235 ); + } + if ( self.a_uts_open_craftables_available.size < 2 ) + { + self notify( "kill_choose_open_craftable" ); + self.b_open_craftable_checking_input = 0; + n_entitynum = player getentitynumber(); + if ( isDefined( self.opencraftablehudelem ) && isDefined( self.opencraftablehudelem[ n_entitynum ] ) ) + { + self.opencraftablehudelem[ n_entitynum ] destroy(); + } + } + switch( self.a_uts_open_craftables_available.size ) + { + case 0: + if ( !isDefined( player.current_craftable_piece ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_MORE"; + self.n_open_craftable_choice = -1; + return 0; + } + case 1: + self.n_open_craftable_choice = 0; + self.equipname = self.a_uts_open_craftables_available[ self.n_open_craftable_choice ].equipname; + return 1; + default: + if ( !self.b_open_craftable_checking_input ) + { + thread choose_open_craftable( player ); + } + return 1; + } + } + else + { + if ( self.persistent == 1 ) + { + return 1; + } + } + return 0; + } +} + +player_continue_crafting( craftablespawn ) +{ + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || self in_revive_trigger() ) + { + return 0; + } + if ( !self player_can_craft( craftablespawn, 1 ) ) + { + return 0; + } + if ( isDefined( self.screecher ) ) + { + return 0; + } + if ( !self usebuttonpressed() ) + { + return 0; + } + if ( !craftablespawn craftable_is_piece_crafting( self.current_craftable_piece ) ) + { + return 0; + } + trigger = craftablespawn.stub maps/mp/zombies/_zm_unitrigger::unitrigger_trigger( self ); + if ( craftablespawn.stub.script_unitrigger_type == "unitrigger_radius_use" ) + { + torigin = craftablespawn.stub unitrigger_origin(); + porigin = self geteye(); + radius_sq = 2,25 * craftablespawn.stub.radius * craftablespawn.stub.radius; + if ( distance2dsquared( torigin, porigin ) > radius_sq ) + { + return 0; + } + } + else + { + if ( !isDefined( trigger ) || !trigger istouching( self ) ) + { + return 0; + } + } + if ( isDefined( craftablespawn.stub.require_look_at ) && craftablespawn.stub.require_look_at && !self is_player_looking_at( trigger.origin, 0,76 ) ) + { + return 0; + } + return 1; +} + +player_progress_bar_update( start_time, craft_time ) +{ + self endon( "entering_last_stand" ); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "craftable_progress_end" ); + while ( isDefined( self ) && ( getTime() - start_time ) < craft_time ) + { + progress = ( getTime() - start_time ) / craft_time; + if ( progress < 0 ) + { + progress = 0; + } + if ( progress > 1 ) + { + progress = 1; + } + self.usebar updatebar( progress ); + wait 0,05; + } +} + +player_progress_bar( start_time, craft_time ) +{ + self.usebar = self createprimaryprogressbar(); + self.usebartext = self createprimaryprogressbartext(); + self.usebartext settext( &"ZOMBIE_BUILDING" ); + if ( isDefined( self ) && isDefined( start_time ) && isDefined( craft_time ) ) + { + self player_progress_bar_update( start_time, craft_time ); + } + self.usebartext destroyelem(); + self.usebar destroyelem(); +} + +craftable_use_hold_think_internal( player ) +{ + wait 0,01; + if ( !isDefined( self ) ) + { + self notify( "craft_failed" ); + if ( isDefined( player.craftableaudio ) ) + { + player.craftableaudio delete(); + player.craftableaudio = undefined; + } + return; + } + if ( !isDefined( self.usetime ) ) + { + self.usetime = int( 3000 ); + } + self.craft_time = self.usetime; + self.craft_start_time = getTime(); + craft_time = self.craft_time; + craft_start_time = self.craft_start_time; + player disable_player_move_states( 1 ); + player increment_is_drinking(); + orgweapon = player getcurrentweapon(); + player giveweapon( "zombie_builder_zm" ); + player switchtoweapon( "zombie_builder_zm" ); + self.stub.craftablespawn craftable_set_piece_crafting( player.current_craftable_piece ); + player thread player_progress_bar( craft_start_time, craft_time ); + if ( isDefined( level.craftable_craft_custom_func ) ) + { + player thread [[ level.craftable_craft_custom_func ]]( self.stub ); + } + while ( isDefined( self ) && player player_continue_crafting( self.stub.craftablespawn ) && ( getTime() - self.craft_start_time ) < self.craft_time ) + { + wait 0,05; + } + player notify( "craftable_progress_end" ); + player maps/mp/zombies/_zm_weapons::switch_back_primary_weapon( orgweapon ); + player takeweapon( "zombie_builder_zm" ); + if ( isDefined( player.is_drinking ) && player.is_drinking ) + { + player decrement_is_drinking(); + } + player enable_player_move_states(); + if ( isDefined( self ) && player player_continue_crafting( self.stub.craftablespawn ) && ( getTime() - self.craft_start_time ) >= self.craft_time ) + { + self.stub.craftablespawn craftable_clear_piece_crafting( player.current_craftable_piece ); + self notify( "craft_succeed" ); + } + else + { + if ( isDefined( player.craftableaudio ) ) + { + player.craftableaudio delete(); + player.craftableaudio = undefined; + } + self.stub.craftablespawn craftable_clear_piece_crafting( player.current_craftable_piece ); + self notify( "craft_failed" ); + } +} + +craftable_play_craft_fx( player ) +{ + self endon( "kill_trigger" ); + self endon( "craft_succeed" ); + self endon( "craft_failed" ); + while ( 1 ) + { + playfx( level._effect[ "building_dust" ], player getplayercamerapos(), player.angles ); + wait 0,5; + } +} + +craftable_use_hold_think( player ) +{ + self thread craftable_play_craft_fx( player ); + self thread craftable_use_hold_think_internal( player ); + retval = self waittill_any_return( "craft_succeed", "craft_failed" ); + if ( retval == "craft_succeed" ) + { + return 1; + } + return 0; +} + +craftable_place_think() +{ + self endon( "kill_trigger" ); + player_crafted = undefined; + while ( isDefined( self.stub.crafted ) && !self.stub.crafted ) + { + self waittill( "trigger", player ); + while ( isDefined( level.custom_craftable_validation ) ) + { + valid = self [[ level.custom_craftable_validation ]]( player ); + while ( !valid ) + { + continue; + } + } + while ( player != self.parent_player ) + { + continue; + } + while ( isDefined( player.screecher_weapon ) ) + { + continue; + } + while ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + status = player player_can_craft( self.stub.craftablespawn ); + if ( !status ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + if ( isDefined( self.stub.oncantuse ) ) + { + self.stub [[ self.stub.oncantuse ]]( player ); + } + continue; + } + else + { + if ( isDefined( self.stub.onbeginuse ) ) + { + self.stub [[ self.stub.onbeginuse ]]( player ); + } + result = self craftable_use_hold_think( player ); + team = player.pers[ "team" ]; + if ( isDefined( self.stub.onenduse ) ) + { + self.stub [[ self.stub.onenduse ]]( team, player, result ); + } + while ( !result ) + { + continue; + } + if ( isDefined( self.stub.onuse ) ) + { + self.stub [[ self.stub.onuse ]]( player ); + } + prompt = player player_craft( self.stub.craftablespawn ); + player_crafted = player; + self.stub.hint_string = prompt; + self sethintstring( self.stub.hint_string ); + } + } + if ( isDefined( self.stub.craftablestub.onfullycrafted ) ) + { + b_result = self.stub [[ self.stub.craftablestub.onfullycrafted ]](); + if ( !b_result ) + { + return; + } + } + if ( isDefined( player_crafted ) ) + { + } + if ( self.stub.persistent == 0 ) + { + self.stub craftablestub_remove(); + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.stub ); + return; + } + if ( self.stub.persistent == 3 ) + { + stub_uncraft_craftable( self.stub, 1 ); + return; + } + if ( self.stub.persistent == 2 ) + { + if ( isDefined( player_crafted ) ) + { + self craftabletrigger_update_prompt( player_crafted ); + } + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.stub.weaponname, undefined ) ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + self sethintstring( self.stub.hint_string ); + return; + } + if ( isDefined( self.stub.str_taken ) && self.stub.str_taken ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX"; + self sethintstring( self.stub.hint_string ); + return; + } + if ( isDefined( self.stub.model ) ) + { + self.stub.model notsolid(); + self.stub.model show(); + } + while ( self.stub.persistent == 2 ) + { + self waittill( "trigger", player ); + while ( isDefined( player.screecher_weapon ) ) + { + continue; + } + while ( isDefined( level.custom_craftable_validation ) ) + { + valid = self [[ level.custom_craftable_validation ]]( player ); + while ( !valid ) + { + continue; + } + } + if ( isDefined( self.stub.crafted ) && !self.stub.crafted ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + return; + } + while ( player != self.parent_player ) + { + continue; + } + while ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + self.stub.bought = 1; + if ( isDefined( self.stub.model ) ) + { + self.stub.model thread model_fly_away(); + } + player maps/mp/zombies/_zm_weapons::weapon_give( self.stub.weaponname ); + if ( isDefined( level.zombie_include_craftables[ self.stub.equipname ].onbuyweapon ) ) + { + self [[ level.zombie_include_craftables[ self.stub.equipname ].onbuyweapon ]]( player ); + } + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.stub.weaponname, undefined ) ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + } + else + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX"; + } + self sethintstring( self.stub.hint_string ); + player track_craftables_pickedup( self.stub.weaponname ); + } + } + else while ( !isDefined( player_crafted ) || self craftabletrigger_update_prompt( player_crafted ) ) + { + if ( isDefined( self.stub.model ) ) + { + self.stub.model notsolid(); + self.stub.model show(); + } + while ( self.stub.persistent == 1 ) + { + self waittill( "trigger", player ); + while ( isDefined( player.screecher_weapon ) ) + { + continue; + } + while ( isDefined( level.custom_craftable_validation ) ) + { + valid = self [[ level.custom_craftable_validation ]]( player ); + while ( !valid ) + { + continue; + } + } + if ( isDefined( self.stub.crafted ) && !self.stub.crafted ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + return; + } + while ( player != self.parent_player ) + { + continue; + } + while ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + while ( player has_player_equipment( self.stub.weaponname ) ) + { + continue; + } + if ( !maps/mp/zombies/_zm_equipment::is_limited_equipment( self.stub.weaponname ) || !maps/mp/zombies/_zm_equipment::limited_equipment_in_use( self.stub.weaponname ) ) + { + player maps/mp/zombies/_zm_equipment::equipment_buy( self.stub.weaponname ); + player giveweapon( self.stub.weaponname ); + player setweaponammoclip( self.stub.weaponname, 1 ); + if ( isDefined( level.zombie_include_craftables[ self.stub.equipname ].onbuyweapon ) ) + { + self [[ level.zombie_include_craftables[ self.stub.equipname ].onbuyweapon ]]( player ); + } + if ( self.stub.weaponname != "keys_zm" ) + { + player setactionslot( 1, "weapon", self.stub.weaponname ); + } + if ( isDefined( level.zombie_craftablestubs[ self.stub.equipname ].str_taken ) ) + { + self.stub.hint_string = level.zombie_craftablestubs[ self.stub.equipname ].str_taken; + } + else + { + self.stub.hint_string = ""; + } + self sethintstring( self.stub.hint_string ); + player track_craftables_pickedup( self.stub.craftablespawn ); + continue; + } + else + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + } + } + } +} + +model_fly_away() +{ + self moveto( self.origin + vectorScale( ( 0, 0, 1 ), 40 ), 3 ); + direction = self.origin; + direction = ( direction[ 1 ], direction[ 0 ], 0 ); + if ( direction[ 1 ] < 0 || direction[ 0 ] > 0 && direction[ 1 ] > 0 ) + { + direction = ( direction[ 0 ], direction[ 1 ] * -1, 0 ); + } + else + { + if ( direction[ 0 ] < 0 ) + { + direction = ( direction[ 0 ] * -1, direction[ 1 ], 0 ); + } + } + self vibrate( direction, 10, 0,5, 4 ); + self waittill( "movedone" ); + self ghost(); + playfx( level._effect[ "poltergeist" ], self.origin ); +} + +find_craftable_stub( equipname ) +{ + _a2752 = level.a_uts_craftables; + _k2752 = getFirstArrayKey( _a2752 ); + while ( isDefined( _k2752 ) ) + { + stub = _a2752[ _k2752 ]; + if ( stub.equipname == equipname ) + { + return stub; + } + _k2752 = getNextArrayKey( _a2752, _k2752 ); + } + return undefined; +} + +uncraft_craftable( equipname, return_pieces, origin, angles ) +{ + stub = find_craftable_stub( equipname ); + stub_uncraft_craftable( stub, return_pieces, origin, angles ); +} + +stub_uncraft_craftable( stub, return_pieces, origin, angles, use_random_start ) +{ + if ( isDefined( stub ) ) + { + craftable = stub.craftablespawn; + craftable.crafted = 0; + craftable.stub.crafted = 0; + craftable notify( "uncrafted" ); + level.craftables_crafted[ craftable.craftable_name ] = 0; + level notify( craftable.craftable_name + "_uncrafted" ); + i = 0; + while ( i < craftable.a_piecespawns.size ) + { + craftable.a_piecespawns[ i ].crafted = 0; + if ( isDefined( craftable.a_piecespawns[ i ].tag_name ) ) + { + craftable.stub.model notsolid(); + if ( isDefined( craftable.a_piecespawns[ i ].crafted ) && !craftable.a_piecespawns[ i ].crafted ) + { + craftable.stub.model hidepart( craftable.a_piecespawns[ i ].tag_name ); + break; + } + else + { + craftable.stub.model show(); + craftable.stub.model showpart( craftable.a_piecespawns[ i ].tag_name ); + } + } + if ( isDefined( return_pieces ) && return_pieces ) + { + craftable.a_piecespawns[ i ] piece_spawn_at( origin, angles, use_random_start ); + } + i++; + } + if ( isDefined( craftable.stub.model ) ) + { + craftable.stub.model ghost(); + } + } +} + +player_explode_craftable( equipname, origin, speed, return_to_spawn, return_time ) +{ + self explosiondamage( 50, origin ); + stub = find_craftable_stub( equipname ); + if ( isDefined( stub ) ) + { + craftable = stub.craftablespawn; + craftable.crafted = 0; + craftable.stub.crafted = 0; + craftable notify( "uncrafted" ); + level.craftables_crafted[ craftable.craftable_name ] = 0; + level notify( craftable.craftable_name + "_uncrafted" ); + i = 0; + while ( i < craftable.a_piecespawns.size ) + { + craftable.a_piecespawns[ i ].crafted = 0; + if ( isDefined( craftable.a_piecespawns[ i ].tag_name ) ) + { + craftable.stub.model notsolid(); + if ( isDefined( craftable.a_piecespawns[ i ].crafted ) && !craftable.a_piecespawns[ i ].crafted ) + { + craftable.stub.model hidepart( craftable.a_piecespawns[ i ].tag_name ); + break; + } + else + { + craftable.stub.model show(); + craftable.stub.model showpart( craftable.a_piecespawns[ i ].tag_name ); + } + } + ang = randomfloat( 360 ); + h = 0,25 + randomfloat( 0,5 ); + dir = ( sin( ang ), cos( ang ), h ); + self thread player_throw_piece( craftable.a_piecespawns[ i ], origin, speed * dir, return_to_spawn, return_time ); + i++; + } + craftable.stub.model ghost(); + } +} + +think_craftables() +{ + _a2850 = level.zombie_include_craftables; + _k2850 = getFirstArrayKey( _a2850 ); + while ( isDefined( _k2850 ) ) + { + craftable = _a2850[ _k2850 ]; + if ( isDefined( craftable.triggerthink ) ) + { + craftable [[ craftable.triggerthink ]](); + } + _k2850 = getNextArrayKey( _a2850, _k2850 ); + } +} + +opentablecraftable() +{ + a_trigs = getentarray( "open_craftable_trigger", "targetname" ); + _a2864 = a_trigs; + _k2864 = getFirstArrayKey( _a2864 ); + while ( isDefined( _k2864 ) ) + { + trig = _a2864[ _k2864 ]; + setup_unitrigger_craftable_internal( trig, "open_table", "", "OPEN_CRAFTABLE", 1, 0 ); + _k2864 = getNextArrayKey( _a2864, _k2864 ); + } +} + +craftable_trigger_think( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + return setup_unitrigger_craftable( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +craftable_trigger_think_array( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + return setup_unitrigger_craftable_array( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +setup_vehicle_unitrigger_craftable( parent, trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + trig = getent( trigger_targetname, "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.craftablestub = level.zombie_include_craftables[ equipname ]; + unitrigger_stub.link_parent = parent; + unitrigger_stub.origin_parent = trig; + unitrigger_stub.trigger_targetname = trigger_targetname; + unitrigger_stub.originfunc = ::anystub_get_unitrigger_origin; + unitrigger_stub.onspawnfunc = ::anystub_on_spawn_trigger; + unitrigger_stub.origin = trig.origin; + unitrigger_stub.angles = trig.angles; + unitrigger_stub.equipname = equipname; + unitrigger_stub.weaponname = weaponname; + unitrigger_stub.trigger_hintstring = trigger_hintstring; + unitrigger_stub.delete_trigger = delete_trigger; + unitrigger_stub.crafted = 0; + unitrigger_stub.persistent = persistent; + unitrigger_stub.usetime = int( 3000 ); + unitrigger_stub.onbeginuse = ::onbeginuseuts; + unitrigger_stub.onenduse = ::onenduseuts; + unitrigger_stub.onuse = ::onuseplantobjectuts; + unitrigger_stub.oncantuse = ::oncantuseuts; + if ( isDefined( trig.script_length ) ) + { + unitrigger_stub.script_length = trig.script_length; + } + else + { + unitrigger_stub.script_length = 24; + } + if ( isDefined( trig.script_width ) ) + { + unitrigger_stub.script_width = trig.script_width; + } + else + { + unitrigger_stub.script_width = 64; + } + if ( isDefined( trig.script_height ) ) + { + unitrigger_stub.script_height = trig.script_height; + } + else + { + unitrigger_stub.script_height = 24; + } + if ( isDefined( trig.radius ) ) + { + unitrigger_stub.radius = trig.radius; + } + else + { + unitrigger_stub.radius = 64; + } + unitrigger_stub.target = trig.target; + unitrigger_stub.targetname = trig.targetname + "_trigger"; + unitrigger_stub.script_noteworthy = trig.script_noteworthy; + unitrigger_stub.script_parameters = trig.script_parameters; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + if ( isDefined( level.zombie_craftablestubs[ equipname ].str_to_craft ) ) + { + unitrigger_stub.hint_string = level.zombie_craftablestubs[ equipname ].str_to_craft; + } + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + unitrigger_stub.require_look_at = 1; + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + unitrigger_stub.prompt_and_visibility_func = ::craftabletrigger_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_unitrigger( unitrigger_stub, ::craftable_place_think ); + unitrigger_stub.piece_trigger = trig; + trig.trigger_stub = unitrigger_stub; + unitrigger_stub.craftablespawn = unitrigger_stub craftable_piece_unitriggers( equipname, unitrigger_stub.origin ); + if ( delete_trigger ) + { + trig delete(); + } + level.a_uts_craftables[ level.a_uts_craftables.size ] = unitrigger_stub; + return unitrigger_stub; +} + +vehicle_craftable_trigger_think( vehicle, trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + return setup_vehicle_unitrigger_craftable( vehicle, trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +onpickuputs( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece recovered by - " + player.name ); +#/ + } +} + +ondroputs( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece dropped by - " + player.name ); +#/ + } + player notify( "event_ended" ); +} + +onbeginuseuts( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece begin use by - " + player.name ); +#/ + } + if ( isDefined( self.craftablestub.onbeginuse ) ) + { + self [[ self.craftablestub.onbeginuse ]]( player ); + } + if ( isDefined( player ) && !isDefined( player.craftableaudio ) ) + { + player.craftableaudio = spawn( "script_origin", player.origin ); + player.craftableaudio playloopsound( "zmb_craftable_loop" ); + } +} + +onenduseuts( team, player, result ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece end use by - " + player.name ); +#/ + } + if ( !isDefined( player ) ) + { + return; + } + if ( isDefined( player.craftableaudio ) ) + { + player.craftableaudio delete(); + player.craftableaudio = undefined; + } + if ( isDefined( self.craftablestub.onenduse ) ) + { + self [[ self.craftablestub.onenduse ]]( team, player, result ); + } + player notify( "event_ended" ); +} + +oncantuseuts( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece can't use by - " + player.name ); +#/ + } + if ( isDefined( self.craftablestub.oncantuse ) ) + { + self [[ self.craftablestub.oncantuse ]]( player ); + } +} + +onuseplantobjectuts( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece crafted by - " + player.name ); +#/ + } + if ( isDefined( self.craftablestub.onuseplantobject ) ) + { + self [[ self.craftablestub.onuseplantobject ]]( player ); + } + player notify( "bomb_planted" ); +} + +is_craftable() +{ + if ( !isDefined( level.zombie_craftablestubs ) ) + { + return 0; + } + if ( isDefined( self.zombie_weapon_upgrade ) && isDefined( level.zombie_craftablestubs[ self.zombie_weapon_upgrade ] ) ) + { + return 1; + } + if ( isDefined( self.script_noteworthy ) && self.script_noteworthy == "specialty_weapupgrade" ) + { + if ( isDefined( level.craftables_crafted[ "pap" ] ) && level.craftables_crafted[ "pap" ] ) + { + return 0; + } + return 1; + } + return 0; +} + +craftable_crafted() +{ + self.a_piecespawns--; + +} + +craftable_complete() +{ + if ( self.a_piecespawns <= 0 ) + { + return 1; + } + return 0; +} + +get_craftable_hint( craftable_name ) +{ +/# + assert( isDefined( level.zombie_craftablestubs[ craftable_name ] ), craftable_name + " was not included or is not part of the zombie weapon list." ); +#/ + return level.zombie_craftablestubs[ craftable_name ].str_to_craft; +} + +delete_on_disconnect( craftable, self_notify, skip_delete ) +{ + craftable endon( "death" ); + self waittill( "disconnect" ); + if ( isDefined( self_notify ) ) + { + self notify( self_notify ); + } + if ( isDefined( skip_delete ) && !skip_delete ) + { + if ( isDefined( craftable.stub ) ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( craftable.stub ); + craftable.stub = undefined; + } + if ( isDefined( craftable ) ) + { + craftable delete(); + } + } +} + +is_holding_part( craftable_name, piece_name ) +{ + if ( isDefined( self.current_craftable_piece ) ) + { + if ( self.current_craftable_piece.craftablename == craftable_name && self.current_craftable_piece.modelname == piece_name ) + { + return 1; + } + } + while ( isDefined( level.a_uts_craftables ) ) + { + _a3223 = level.a_uts_craftables; + _k3223 = getFirstArrayKey( _a3223 ); + while ( isDefined( _k3223 ) ) + { + craftable_stub = _a3223[ _k3223 ]; + while ( craftable_stub.craftablestub.name == craftable_name ) + { + _a3228 = craftable_stub.craftablespawn.a_piecespawns; + _k3228 = getFirstArrayKey( _a3228 ); + while ( isDefined( _k3228 ) ) + { + piece = _a3228[ _k3228 ]; + if ( piece.piecename == piece_name ) + { + if ( isDefined( piece.in_shared_inventory ) && piece.in_shared_inventory ) + { + return 1; + } + } + _k3228 = getNextArrayKey( _a3228, _k3228 ); + } + } + _k3223 = getNextArrayKey( _a3223, _k3223 ); + } + } + return 0; +} + +is_part_crafted( craftable_name, piece_name ) +{ + while ( isDefined( level.a_uts_craftables ) ) + { + _a3253 = level.a_uts_craftables; + _k3253 = getFirstArrayKey( _a3253 ); + while ( isDefined( _k3253 ) ) + { + craftable_stub = _a3253[ _k3253 ]; + while ( craftable_stub.craftablestub.name == craftable_name ) + { + if ( isDefined( craftable_stub.crafted ) && craftable_stub.crafted ) + { + return 1; + } + _a3264 = craftable_stub.craftablespawn.a_piecespawns; + _k3264 = getFirstArrayKey( _a3264 ); + while ( isDefined( _k3264 ) ) + { + piece = _a3264[ _k3264 ]; + if ( piece.piecename == piece_name ) + { + if ( isDefined( piece.crafted ) && piece.crafted ) + { + return 1; + } + } + _k3264 = getNextArrayKey( _a3264, _k3264 ); + } + } + _k3253 = getNextArrayKey( _a3253, _k3253 ); + } + } + return 0; +} + +track_craftable_piece_pickedup( piece ) +{ + if ( !isDefined( piece ) || !isDefined( piece.craftablename ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_craftable_piece_pickedup() \n" ); +#/ + return; + } + self add_map_craftable_stat( piece.craftablename, "pieces_pickedup", 1 ); + if ( isDefined( piece.piecestub.vox_id ) ) + { + self thread do_player_general_vox( "general", piece.piecestub.vox_id + "_pickup" ); + } + else + { + self thread do_player_general_vox( "general", "build_pickup" ); + } +} + +track_craftable_pieces_crafted( craftable ) +{ + if ( !isDefined( craftable ) || !isDefined( craftable.craftable_name ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_craftable_pieces_crafted() \n" ); +#/ + return; + } + bname = craftable.craftable_name; + if ( isDefined( craftable.stat_name ) ) + { + bname = craftable.stat_name; + } + self add_map_craftable_stat( bname, "pieces_built", 1 ); + if ( !craftable craftable_all_crafted() ) + { + self thread do_player_general_vox( "general", "build_add" ); + } +} + +track_craftables_crafted( craftable ) +{ + if ( !isDefined( craftable ) || !isDefined( craftable.craftable_name ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_craftables_crafted() \n" ); +#/ + return; + } + bname = craftable.craftable_name; + if ( isDefined( craftable.stat_name ) ) + { + bname = craftable.stat_name; + } + self add_map_craftable_stat( bname, "buildable_built", 1 ); + self maps/mp/zombies/_zm_stats::increment_client_stat( "buildables_built", 0 ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "buildables_built" ); + if ( isDefined( craftable.stub.craftablestub.vox_id ) ) + { + self thread do_player_general_vox( "general", craftable.stub.craftablestub.vox_id + "_final" ); + } +} + +track_craftables_pickedup( craftable ) +{ + if ( !isDefined( craftable ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_craftables_pickedup() \n" ); +#/ + return; + } + stat_name = get_craftable_stat_name( craftable.craftable_name ); + if ( !isDefined( stat_name ) ) + { +/# + println( "STAT TRACKING FAILURE: NO STAT NAME FOR " + craftable.craftable_name + "\n" ); +#/ + return; + } + self add_map_craftable_stat( stat_name, "buildable_pickedup", 1 ); + if ( isDefined( craftable.stub.craftablestub.vox_id ) ) + { + self thread do_player_general_vox( "general", craftable.stub.craftablestub.vox_id + "_plc" ); + } + self say_pickup_craftable_vo( craftable, 0 ); +} + +track_craftables_planted( equipment ) +{ + if ( !isDefined( equipment ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED for track_craftables_planted() \n" ); +#/ + return; + } + craftable_name = undefined; + if ( isDefined( equipment.name ) ) + { + craftable_name = get_craftable_stat_name( equipment.name ); + } + if ( !isDefined( craftable_name ) ) + { +/# + println( "STAT TRACKING FAILURE: NO CRAFTABLE NAME FOR track_craftables_planted() " + equipment.name + "\n" ); +#/ + return; + } + maps/mp/_demo::bookmark( "zm_player_buildable_placed", getTime(), self ); + self add_map_craftable_stat( craftable_name, "buildable_placed", 1 ); +} + +placed_craftable_vo_timer() +{ + self endon( "disconnect" ); + self.craftable_timer = 1; + wait 60; + self.craftable_timer = 0; +} + +craftable_pickedup_timer() +{ + self endon( "disconnect" ); + self.craftable_pickedup_timer = 1; + wait 60; + self.craftable_pickedup_timer = 0; +} + +track_planted_craftables_pickedup( equipment ) +{ + if ( !isDefined( equipment ) ) + { + return; + } + if ( equipment != "equip_turbine_zm" && equipment != "equip_turret_zm" && equipment != "equip_electrictrap_zm" || equipment == "riotshield_zm" && equipment == "alcatraz_shield_zm" ) + { + self maps/mp/zombies/_zm_stats::increment_client_stat( "planted_buildables_pickedup", 0 ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "planted_buildables_pickedup" ); + } + if ( isDefined( self.craftable_pickedup_timer ) && !self.craftable_pickedup_timer ) + { + self say_pickup_craftable_vo( equipment, 1 ); + self thread craftable_pickedup_timer(); + } +} + +track_placed_craftables( craftable_name ) +{ + if ( !isDefined( craftable_name ) ) + { + return; + } + self add_map_craftable_stat( craftable_name, "buildable_placed", 1 ); + vo_name = undefined; + if ( craftable_name == level.riotshield_name ) + { + vo_name = "craft_plc_shield"; + } + if ( !isDefined( vo_name ) ) + { + return; + } + self thread do_player_general_vox( "general", vo_name ); +} + +add_map_craftable_stat( piece_name, stat_name, value ) +{ + if ( isDefined( piece_name ) || piece_name == "sq_common" && piece_name == "keys_zm" ) + { + return; + } + self adddstat( "buildables", piece_name, stat_name, value ); +} + +say_pickup_craftable_vo( craftable_name, world ) +{ +} + +get_craftable_vo_name( craftable_name ) +{ +} + +get_craftable_stat_name( craftable_name ) +{ + if ( isDefined( craftable_name ) ) + { + switch( craftable_name ) + { + case "equip_riotshield_zm": + return "riotshield_zm"; + case "equip_turbine_zm": + return "turbine"; + case "equip_turret_zm": + return "turret"; + case "equip_electrictrap_zm": + return "electric_trap"; + case "equip_springpad_zm": + return "springpad_zm"; + case "equip_slipgun_zm": + return "slipgun_zm"; + } + } + return craftable_name; +} + +get_craftable_model( str_craftable ) +{ + _a3544 = level.a_uts_craftables; + _k3544 = getFirstArrayKey( _a3544 ); + while ( isDefined( _k3544 ) ) + { + uts_craftable = _a3544[ _k3544 ]; + if ( uts_craftable.craftablestub.name == str_craftable ) + { + if ( isDefined( uts_craftable.model ) ) + { + return uts_craftable.model; + } + } + else + { + _k3544 = getNextArrayKey( _a3544, _k3544 ); + } + } + return undefined; +} + +get_craftable_piece( str_craftable, str_piece ) +{ + _a3564 = level.a_uts_craftables; + _k3564 = getFirstArrayKey( _a3564 ); + while ( isDefined( _k3564 ) ) + { + uts_craftable = _a3564[ _k3564 ]; + if ( uts_craftable.craftablestub.name == str_craftable ) + { + _a3568 = uts_craftable.craftablespawn.a_piecespawns; + _k3568 = getFirstArrayKey( _a3568 ); + while ( isDefined( _k3568 ) ) + { + piecespawn = _a3568[ _k3568 ]; + if ( piecespawn.piecename == str_piece ) + { + return piecespawn; + } + _k3568 = getNextArrayKey( _a3568, _k3568 ); + } + } + else _k3564 = getNextArrayKey( _a3564, _k3564 ); + } + return undefined; +} + +player_get_craftable_piece( str_craftable, str_piece ) +{ + piecespawn = get_craftable_piece( str_craftable, str_piece ); + if ( isDefined( piecespawn ) ) + { + self player_take_piece( piecespawn ); + } +} + +get_craftable_piece_model( str_craftable, str_piece ) +{ + _a3600 = level.a_uts_craftables; + _k3600 = getFirstArrayKey( _a3600 ); + while ( isDefined( _k3600 ) ) + { + uts_craftable = _a3600[ _k3600 ]; + if ( uts_craftable.craftablestub.name == str_craftable ) + { + _a3604 = uts_craftable.craftablespawn.a_piecespawns; + _k3604 = getFirstArrayKey( _a3604 ); + while ( isDefined( _k3604 ) ) + { + piecespawn = _a3604[ _k3604 ]; + if ( piecespawn.piecename == str_piece && isDefined( piecespawn.model ) ) + { + return piecespawn.model; + } + _k3604 = getNextArrayKey( _a3604, _k3604 ); + } + } + else _k3600 = getNextArrayKey( _a3600, _k3600 ); + } + return undefined; +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_game_module_grief.gsc b/zm_prison_patch/maps/mp/zombies/_zm_game_module_grief.gsc new file mode 100644 index 0000000..14a2eba --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_game_module_grief.gsc @@ -0,0 +1,11 @@ +#include maps/mp/zombies/_zm_game_module_utility; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/_utility; + +register_game_module() +{ + level.game_module_grief_index = 9; + maps/mp/zombies/_zm_game_module::register_game_module( level.game_module_grief_index, "zgrief", ::onpreinitgametype, ::onpostinitgametype, undefined, ::onspawnzombie, ::onstartgametype ); +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_game_module_meat.gsc b/zm_prison_patch/maps/mp/zombies/_zm_game_module_meat.gsc new file mode 100644 index 0000000..e083fb3 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_game_module_meat.gsc @@ -0,0 +1,6 @@ +#include maps/mp/zombies/_zm_game_module_utility; +#include maps/mp/zombies/_zm_game_module_meat_utility; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/_utility; diff --git a/zm_prison_patch/maps/mp/zombies/_zm_game_module_meat_utility.gsc b/zm_prison_patch/maps/mp/zombies/_zm_game_module_meat_utility.gsc new file mode 100644 index 0000000..101f026 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_game_module_meat_utility.gsc @@ -0,0 +1,685 @@ +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/gametypes_zm/zmeat; +#include maps/mp/zombies/_zm_audio_announcer; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_game_module_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +award_grenades_for_team( team ) +{ + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ]._meat_team ) || players[ i ]._meat_team != team ) + { + i++; + continue; + } + else + { + lethal_grenade = players[ i ] get_player_lethal_grenade(); + players[ i ] giveweapon( lethal_grenade ); + players[ i ] setweaponammoclip( lethal_grenade, 4 ); + } + i++; + } +} + +get_players_on_meat_team( team ) +{ + players = get_players(); + players_on_team = []; + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ]._meat_team ) || players[ i ]._meat_team != team ) + { + i++; + continue; + } + else + { + players_on_team[ players_on_team.size ] = players[ i ]; + } + i++; + } + return players_on_team; +} + +get_alive_players_on_meat_team( team ) +{ + players = get_players(); + players_on_team = []; + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ]._meat_team ) || players[ i ]._meat_team != team ) + { + i++; + continue; + } + else + { + if ( players[ i ].sessionstate == "spectator" || players[ i ] maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + i++; + continue; + } + else + { + players_on_team[ players_on_team.size ] = players[ i ]; + } + } + i++; + } + return players_on_team; +} + +init_minigun_ring() +{ + if ( isDefined( level._minigun_ring ) ) + { + return; + } + ring_pos = getstruct( level._meat_location + "_meat_minigun", "script_noteworthy" ); + if ( !isDefined( ring_pos ) ) + { + return; + } + level._minigun_ring = spawn( "script_model", ring_pos.origin ); + level._minigun_ring.angles = ring_pos.angles; + level._minigun_ring setmodel( ring_pos.script_parameters ); + level._minigun_ring_clip = getent( level._meat_location + "_meat_minigun_clip", "script_noteworthy" ); + if ( isDefined( level._minigun_ring_clip ) ) + { + level._minigun_ring_clip linkto( level._minigun_ring ); + } + else + { + iprintlnbold( "BUG: no level._minigun_ring_clip" ); + } + level._minigun_ring_trig = getent( level._meat_location + "_meat_minigun_trig", "targetname" ); + if ( isDefined( level._minigun_ring_trig ) ) + { + level._minigun_ring_trig enablelinkto(); + level._minigun_ring_trig linkto( level._minigun_ring ); + level._minigun_icon = spawn( "script_model", level._minigun_ring_trig.origin ); + level._minigun_icon setmodel( getweaponmodel( "minigun_zm" ) ); + level._minigun_icon linkto( level._minigun_ring ); + level._minigun_icon setclientfield( "ring_glowfx", 1 ); + level thread ring_toss( level._minigun_ring_trig, "minigun" ); + } + else + { + iprintlnbold( "BUG: no level._minigun_ring_trig" ); + } + level._minigun_ring thread move_ring( ring_pos ); + level._minigun_ring thread rotate_ring( 1 ); +} + +init_ammo_ring() +{ + if ( isDefined( level._ammo_ring ) ) + { + return; + } + name = level._meat_location + "_meat_ammo"; + ring_pos = getstruct( name, "script_noteworthy" ); + if ( !isDefined( ring_pos ) ) + { + return; + } + level._ammo_ring = spawn( "script_model", ring_pos.origin ); + level._ammo_ring.angles = ring_pos.angles; + level._ammo_ring setmodel( ring_pos.script_parameters ); + name = level._meat_location + "_meat_ammo_clip"; + level._ammo_ring_clip = getent( name, "script_noteworthy" ); + if ( isDefined( level._ammo_ring_clip ) ) + { + level._ammo_ring_clip linkto( level._ammo_ring ); + } + else + { + iprintlnbold( "BUG: no level._ammo_ring_clip" ); + } + name = level._meat_location + "_meat_ammo_trig"; + level._ammo_ring_trig = getent( name, "targetname" ); + if ( isDefined( level._ammo_ring_clip ) ) + { + level._ammo_ring_trig enablelinkto(); + level._ammo_ring_trig linkto( level._ammo_ring ); + level._ammo_icon = spawn( "script_model", level._ammo_ring_trig.origin ); + level._ammo_icon setmodel( "zombie_ammocan" ); + level._ammo_icon linkto( level._ammo_ring ); + level._ammo_icon setclientfield( "ring_glowfx", 1 ); + level thread ring_toss( level._ammo_ring_trig, "ammo" ); + } + else + { + iprintlnbold( "BUG: no level._ammo_ring_trig" ); + } + level._ammo_ring thread move_ring( ring_pos ); + level._ammo_ring thread rotate_ring( 1 ); +} + +init_splitter_ring() +{ + if ( isDefined( level._splitter_ring ) ) + { + return; + } + ring_pos = getstruct( level._meat_location + "_meat_splitter", "script_noteworthy" ); + if ( !isDefined( ring_pos ) ) + { + return; + } + level._splitter_ring = spawn( "script_model", ring_pos.origin ); + level._splitter_ring.angles = ring_pos.angles; + level._splitter_ring setmodel( ring_pos.script_parameters ); + level._splitter_ring_trig1 = getent( level._meat_location + "_meat_splitter_trig_1", "targetname" ); + level._splitter_ring_trig2 = getent( level._meat_location + "_meat_splitter_trig_2", "targetname" ); + if ( isDefined( level._splitter_ring_trig1 ) && isDefined( level._splitter_ring_trig2 ) ) + { + level._splitter_ring_trig1 enablelinkto(); + level._splitter_ring_trig2 enablelinkto(); + } + else + { + iprintlnbold( "BUG: missing at least one level._splitter_ring_trig" ); + } + level._splitter_ring notsolid(); + level._meat_icon = spawn( "script_model", level._splitter_ring.origin ); + level._meat_icon setmodel( getweaponmodel( get_gamemode_var( "item_meat_name" ) ) ); + level._meat_icon linkto( level._splitter_ring ); + level._meat_icon setclientfield( "ring_glow_meatfx", 1 ); + if ( isDefined( level._splitter_ring_trig1 ) && isDefined( level._splitter_ring_trig2 ) ) + { + level._splitter_ring_trig1 linkto( level._splitter_ring ); + level._splitter_ring_trig2 linkto( level._splitter_ring ); + level thread ring_toss( level._splitter_ring_trig1, "splitter" ); + level thread ring_toss( level._splitter_ring_trig2, "splitter" ); + } + level._splitter_ring thread move_ring( ring_pos ); +} + +ring_toss( trig, type ) +{ + level endon( "end_game" ); + while ( 1 ) + { + while ( isDefined( level._ring_triggered ) && level._ring_triggered ) + { + wait 0,05; + } + if ( isDefined( level.item_meat ) && isDefined( level.item_meat.meat_is_moving ) && level.item_meat.meat_is_moving ) + { + if ( level.item_meat istouching( trig ) ) + { + level thread ring_toss_prize( type, trig ); + level._ring_triggered = 1; + level thread ring_cooldown(); + } + } + wait 0,05; + } +} + +ring_cooldown() +{ + wait 3; + level._ring_triggered = 0; +} + +ring_toss_prize( type, trig ) +{ + switch( type ) + { + case "splitter": + level thread meat_splitter( trig ); + break; + case "minigun": + level thread minigun_prize( trig ); + break; + case "ammo": + level thread ammo_prize( trig ); + break; + } +} + +meat_splitter( trig ) +{ + level endon( "meat_grabbed" ); + level endon( "meat_kicked" ); + while ( isDefined( level.item_meat ) && level.item_meat istouching( trig ) ) + { + wait 0,05; + } + exit_trig = getent( trig.target, "targetname" ); + exit_struct = getstruct( trig.target, "targetname" ); + while ( isDefined( level.item_meat ) && !level.item_meat istouching( exit_trig ) ) + { + wait 0,05; + } + while ( isDefined( level.item_meat ) && level.item_meat istouching( exit_trig ) ) + { + wait 0,05; + } + if ( !isDefined( level.item_meat ) ) + { + return; + } + playfx( level._effect[ "fw_burst" ], exit_trig.origin ); + flare_dir = vectornormalize( anglesToForward( exit_struct.angles ) ); + velocity = vectorScale( flare_dir, randomintrange( 400, 600 ) ); + velocity1 = ( velocity[ 0 ] + 75, velocity[ 1 ] + 75, randomintrange( 75, 125 ) ); + velocity2 = ( velocity[ 0 ] - 75, velocity[ 1 ] - 75, randomintrange( 75, 125 ) ); + velocity3 = ( velocity[ 0 ], velocity[ 1 ], 100 ); + level._fake_meats = []; + level._meat_splitter_activated = 1; + org = exit_trig.origin; + player = get_players()[ 0 ]; + player._spawning_meat = 1; + player endon( "disconnect" ); + thread split_meat( player, org, velocity1, velocity2, velocity ); + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "meat_ring_splitter", undefined, undefined, 1 ); + wait 0,1; + while ( isDefined( level.splitting_meat ) && level.splitting_meat ) + { + wait 0,05; + } + player._spawning_meat = 0; +} + +split_meat( player, org, vel1, vel2, vel3 ) +{ + level.splitting_meat = 1; + level.item_meat cleanup_meat(); + wait_network_frame(); + level._fake_meats[ level._fake_meats.size ] = player magicgrenadetype( get_gamemode_var( "item_meat_name" ), org, vel1 ); + wait_network_frame(); + level._fake_meats[ level._fake_meats.size ] = player magicgrenadetype( get_gamemode_var( "item_meat_name" ), org, vel2 ); + wait_network_frame(); + level._fake_meats[ level._fake_meats.size ] = player magicgrenadetype( get_gamemode_var( "item_meat_name" ), org, vel3 ); + real_meat = random( level._fake_meats ); + _a330 = level._fake_meats; + _k330 = getFirstArrayKey( _a330 ); + while ( isDefined( _k330 ) ) + { + meat = _a330[ _k330 ]; + if ( real_meat != meat ) + { + meat._fake_meat = 1; + meat thread maps/mp/gametypes_zm/zmeat::delete_on_real_meat_pickup(); + } + else + { + meat._fake_meat = 0; + level.item_meat = meat; + } + _k330 = getNextArrayKey( _a330, _k330 ); + } + level.splitting_meat = 0; +} + +minigun_prize( trig ) +{ + while ( isDefined( level.item_meat ) && level.item_meat istouching( trig ) ) + { + wait 0,05; + } + if ( !isDefined( level.item_meat ) ) + { + return; + } + if ( isDefined( level._minigun_toss_cooldown ) && level._minigun_toss_cooldown ) + { + return; + } + level thread minigun_toss_cooldown(); + if ( !is_player_valid( level._last_person_to_throw_meat ) ) + { + return; + } + level._last_person_to_throw_meat thread maps/mp/zombies/_zm_powerups::powerup_vo( "minigun" ); + level thread maps/mp/zombies/_zm_powerups::minigun_weapon_powerup( level._last_person_to_throw_meat ); + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "meat_ring_minigun", undefined, undefined, 1 ); +} + +ammo_prize( trig ) +{ + while ( isDefined( level.item_meat ) && level.item_meat istouching( trig ) ) + { + wait 0,05; + } + if ( !isDefined( level.item_meat ) ) + { + return; + } + if ( isDefined( level._ammo_toss_cooldown ) && level._ammo_toss_cooldown ) + { + return; + } + playfx( level._effect[ "poltergeist" ], trig.origin ); + level thread ammo_toss_cooldown(); + level._last_person_to_throw_meat thread maps/mp/zombies/_zm_powerups::powerup_vo( "full_ammo" ); + level thread maps/mp/zombies/_zm_powerups::full_ammo_powerup( undefined, level._last_person_to_throw_meat ); + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "meat_ring_ammo", undefined, undefined, 1 ); +} + +minigun_toss_cooldown() +{ + level._minigun_toss_cooldown = 1; + if ( isDefined( level._minigun_icon ) ) + { + level._minigun_icon delete(); + } + waittill_any_or_timeout( 120, "meat_end" ); + playfx( level._effect[ "poltergeist" ], level._minigun_ring_trig.origin ); + level._minigun_icon = spawn( "script_model", level._minigun_ring_trig.origin ); + level._minigun_icon setmodel( getweaponmodel( "minigun_zm" ) ); + level._minigun_icon linkto( level._minigun_ring ); + level._minigun_icon setclientfield( "ring_glowfx", 1 ); + level._minigun_toss_cooldown = 0; +} + +ammo_toss_cooldown() +{ + level._ammo_toss_cooldown = 1; + if ( isDefined( level._ammo_icon ) ) + { + level._ammo_icon delete(); + } + waittill_any_or_timeout( 60, "meat_end" ); + playfx( level._effect[ "poltergeist" ], level._ammo_ring_trig.origin ); + level._ammo_icon = spawn( "script_model", level._ammo_ring_trig.origin ); + level._ammo_icon setmodel( "zombie_ammocan" ); + level._ammo_icon linkto( level._ammo_ring ); + level._ammo_icon setclientfield( "ring_glowfx", 1 ); + level._ammo_toss_cooldown = 0; +} + +wait_for_team_death( team ) +{ + level endon( "meat_end" ); + encounters_team = undefined; + while ( 1 ) + { + wait 1; + while ( isDefined( level._checking_for_save ) && level._checking_for_save ) + { + wait 0,1; + } + alive_team_players = get_alive_players_on_meat_team( team ); + while ( alive_team_players.size > 0 ) + { + encounters_team = alive_team_players[ 0 ]._encounters_team; + } + } + if ( !isDefined( encounters_team ) ) + { + return; + } + winning_team = "A"; + if ( encounters_team == "A" ) + { + winning_team = "B"; + } + level notify( "meat_end" ); +} + +check_should_save_player( team ) +{ + if ( !isDefined( level._meat_on_team ) ) + { + return 0; + } + level._checking_for_save = 1; + players = get_players_on_meat_team( team ); + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( isDefined( level._last_person_to_throw_meat ) && level._last_person_to_throw_meat == player ) + { + while ( isDefined( level.item_meat.meat_is_moving ) && !level.item_meat.meat_is_moving && isDefined( level._meat_splitter_activated ) || level._meat_splitter_activated && isDefined( level.item_meat.meat_is_flying ) && level.item_meat.meat_is_flying ) + { + if ( level._meat_on_team != player._meat_team ) + { + break; + } + else if ( isDefined( level.item_meat.meat_is_rolling ) && level.item_meat.meat_is_rolling && level._meat_on_team == player._meat_team ) + { + break; + } + else + { + wait 0,05; + } + } + if ( !isDefined( player ) ) + { + level._checking_for_save = 0; + return 0; + } + if ( isDefined( player.last_damage_from_zombie_or_player ) && !player.last_damage_from_zombie_or_player ) + { + level._checking_for_save = 0; + return 0; + } + if ( level._meat_on_team != player._meat_team && isDefined( level._last_person_to_throw_meat ) && level._last_person_to_throw_meat == player ) + { + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + level thread revive_saved_player( player ); + return 1; + } + } + } + i++; + } + level._checking_for_save = 0; + return 0; +} + +watch_save_player() +{ + if ( !isDefined( level._meat_on_team ) ) + { + return 0; + } + if ( !isDefined( level._last_person_to_throw_meat ) || level._last_person_to_throw_meat != self ) + { + return 0; + } + level._checking_for_save = 1; + while ( isDefined( level.splitting_meat ) || level.splitting_meat && isDefined( level.item_meat ) && isDefined( level.item_meat.meat_is_moving ) || level.item_meat.meat_is_moving && isDefined( level.item_meat.meat_is_flying ) && level.item_meat.meat_is_flying ) + { + if ( level._meat_on_team != self._meat_team ) + { + } + else if ( isDefined( level.item_meat ) && isDefined( level.item_meat.meat_is_rolling ) && level.item_meat.meat_is_rolling && level._meat_on_team == self._meat_team ) + { + } + else + { + wait 0,05; + } + } + if ( level._meat_on_team != self._meat_team && isDefined( level._last_person_to_throw_meat ) && level._last_person_to_throw_meat == self ) + { + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + level thread revive_saved_player( self ); + return 1; + } + } + level._checking_for_save = 0; + return 0; +} + +revive_saved_player( player ) +{ + player endon( "disconnect" ); + player iprintlnbold( &"ZOMBIE_PLAYER_SAVED" ); + player playsound( level.zmb_laugh_alias ); + wait 0,25; + playfx( level._effect[ "poltergeist" ], player.origin ); + playsoundatposition( "zmb_bolt", player.origin ); + earthquake( 0,5, 0,75, player.origin, 1000 ); + player thread maps/mp/zombies/_zm_laststand::auto_revive( player ); + player._saved_by_throw++; + level._checking_for_save = 0; +} + +get_game_module_players( player ) +{ + return get_players_on_meat_team( player._meat_team ); +} + +item_meat_spawn( origin ) +{ + org = origin; + player = get_players()[ 0 ]; + player._spawning_meat = 1; + player magicgrenadetype( get_gamemode_var( "item_meat_name" ), org, ( 0, 0, 1 ) ); + playsoundatposition( "zmb_spawn_powerup", org ); + wait 0,1; + player._spawning_meat = undefined; +} + +init_item_meat( gametype ) +{ + if ( gametype == "zgrief" ) + { + set_gamemode_var_once( "item_meat_name", "item_meat_zm" ); + set_gamemode_var_once( "item_meat_model", "t6_wpn_zmb_meat_world" ); + } + else + { + set_gamemode_var_once( "item_meat_name", "item_head_zm" ); + set_gamemode_var_once( "item_meat_model", "t6_wpn_zmb_severedhead_world" ); + } + precacheitem( get_gamemode_var( "item_meat_name" ) ); + set_gamemode_var_once( "start_item_meat_name", get_gamemode_var( "item_meat_name" ) ); + level.meat_weaponidx = getweaponindexfromname( get_gamemode_var( "item_meat_name" ) ); + level.meat_pickupsound = getweaponpickupsound( level.meat_weaponidx ); + level.meat_pickupsoundplayer = getweaponpickupsoundplayer( level.meat_weaponidx ); +} + +meat_intro( launch_spot ) +{ + flag_wait( "start_encounters_match_logic" ); + wait 3; + level thread multi_launch( launch_spot ); + launch_meat( launch_spot ); + drop_meat( level._meat_start_point ); + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "meat_drop", undefined, undefined, 1 ); +} + +launch_meat( launch_spot ) +{ + level waittill( "launch_meat" ); + spots = getstructarray( launch_spot, "targetname" ); + if ( isDefined( spots ) && spots.size > 0 ) + { + spot = random( spots ); + meat = spawn( "script_model", spot.origin ); + meat setmodel( "tag_origin" ); + wait_network_frame(); + playfxontag( level._effect[ "fw_trail" ], meat, "tag_origin" ); + meat playloopsound( "zmb_souls_loop", 0,75 ); + dest = spot; + while ( isDefined( dest ) && isDefined( dest.target ) ) + { + new_dest = getstruct( dest.target, "targetname" ); + dest = new_dest; + dist = distance( new_dest.origin, meat.origin ); + time = dist / 700; + meat moveto( new_dest.origin, time ); + meat waittill( "movedone" ); + } + meat playsound( "zmb_souls_end" ); + playfx( level._effect[ "fw_burst" ], meat.origin ); + wait randomfloatrange( 0,2, 0,5 ); + meat playsound( "zmb_souls_end" ); + playfx( level._effect[ "fw_burst" ], meat.origin + ( randomintrange( 50, 150 ), randomintrange( 50, 150 ), randomintrange( -20, 20 ) ) ); + wait randomfloatrange( 0,5, 0,75 ); + meat playsound( "zmb_souls_end" ); + playfx( level._effect[ "fw_burst" ], meat.origin + ( randomintrange( -150, -50 ), randomintrange( -150, 50 ), randomintrange( -20, 20 ) ) ); + wait randomfloatrange( 0,5, 0,75 ); + meat playsound( "zmb_souls_end" ); + playfx( level._effect[ "fw_burst" ], meat.origin ); + meat delete(); + } +} + +multi_launch( launch_spot ) +{ + spots = getstructarray( launch_spot, "targetname" ); + if ( isDefined( spots ) && spots.size > 0 ) + { + x = 0; + while ( x < 3 ) + { + i = 0; + while ( i < spots.size ) + { + delay = randomfloatrange( 0,1, 0,25 ); + level thread fake_launch( spots[ i ], delay ); + i++; + } + wait randomfloatrange( 0,25, 0,75 ); + if ( x > 1 ) + { + level notify( "launch_meat" ); + } + x++; + } + } + else wait randomfloatrange( 0,25, 0,75 ); + level notify( "launch_meat" ); +} + +fake_launch( launch_spot, delay ) +{ + wait delay; + wait randomfloatrange( 0,1, 4 ); + meat = spawn( "script_model", launch_spot.origin + ( randomintrange( -60, 60 ), randomintrange( -60, 60 ), 0 ) ); + meat setmodel( "tag_origin" ); + wait_network_frame(); + playfxontag( level._effect[ "fw_trail_cheap" ], meat, "tag_origin" ); + meat playloopsound( "zmb_souls_loop", 0,75 ); + dest = launch_spot; + while ( isDefined( dest ) && isDefined( dest.target ) ) + { + random_offset = ( randomintrange( -60, 60 ), randomintrange( -60, 60 ), 0 ); + new_dest = getstruct( dest.target, "targetname" ); + dest = new_dest; + dist = distance( new_dest.origin + random_offset, meat.origin ); + time = dist / 700; + meat moveto( new_dest.origin + random_offset, time ); + meat waittill( "movedone" ); + } + meat playsound( "zmb_souls_end" ); + playfx( level._effect[ "fw_pre_burst" ], meat.origin ); + meat delete(); +} + +drop_meat( drop_spot ) +{ + meat = spawn( "script_model", drop_spot + vectorScale( ( 0, 0, 1 ), 600 ) ); + meat setmodel( "tag_origin" ); + dist = distance( meat.origin, drop_spot ); + time = dist / 400; + wait 2; + meat moveto( drop_spot, time ); + wait_network_frame(); + playfxontag( level._effect[ "fw_drop" ], meat, "tag_origin" ); + meat waittill( "movedone" ); + playfx( level._effect[ "fw_impact" ], drop_spot ); + level notify( "reset_meat" ); + meat delete(); +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_game_module_utility.gsc b/zm_prison_patch/maps/mp/zombies/_zm_game_module_utility.gsc new file mode 100644 index 0000000..7c90b48 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_game_module_utility.gsc @@ -0,0 +1,46 @@ +#include maps/mp/zombies/_zm_game_module_meat; +#include maps/mp/zombies/_zm_game_module_meat_utility; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/_utility; + +init_item_meat() +{ + level.item_meat_name = "item_meat_zm"; + precacheitem( level.item_meat_name ); +} + +move_ring( ring ) +{ + positions = getstructarray( ring.target, "targetname" ); + positions = array_randomize( positions ); + level endon( "end_game" ); + while ( 1 ) + { + _a23 = positions; + _k23 = getFirstArrayKey( _a23 ); + while ( isDefined( _k23 ) ) + { + position = _a23[ _k23 ]; + self moveto( position.origin, randomintrange( 30, 45 ) ); + self waittill( "movedone" ); + _k23 = getNextArrayKey( _a23, _k23 ); + } + } +} + +rotate_ring( forward ) +{ + level endon( "end_game" ); + dir = -360; + if ( forward ) + { + dir = 360; + } + while ( 1 ) + { + self rotateyaw( dir, 9 ); + wait 9; + } +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_magicbox_prison.gsc b/zm_prison_patch/maps/mp/zombies/_zm_magicbox_prison.gsc new file mode 100644 index 0000000..991f0a3 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_magicbox_prison.gsc @@ -0,0 +1,217 @@ +#include maps/mp/zombies/_zm_magicbox; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + registerclientfield( "zbarrier", "magicbox_initial_fx", 2000, 1, "int" ); + registerclientfield( "zbarrier", "magicbox_amb_fx", 2000, 2, "int" ); + registerclientfield( "zbarrier", "magicbox_open_fx", 2000, 1, "int" ); + registerclientfield( "zbarrier", "magicbox_leaving_fx", 2000, 1, "int" ); + level._effect[ "lght_marker" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_marker" ); + level._effect[ "lght_marker_flare" ] = loadfx( "maps/zombie_alcatraz/fx_zmb_tranzit_marker_fl" ); + level._effect[ "poltergeist" ] = loadfx( "system_elements/fx_null" ); + level._effect[ "box_gone_ambient" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_magicbox_amb" ); + level._effect[ "box_here_ambient" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_magicbox_arrive" ); + level._effect[ "box_is_open" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_magicbox_open" ); + level._effect[ "box_is_locked" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_magicbox_lock" ); + level._effect[ "box_is_leaving" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_magicbox_leave" ); + level.using_locked_magicbox = 1; + level.chest_joker_model = "p6_anim_zm_al_magic_box_lock_red"; + precachemodel( level.chest_joker_model ); + level.chest_joker_custom_movement = ::custom_joker_movement; + level.magic_box_zbarrier_state_func = ::set_magic_box_zbarrier_state; + level thread wait_then_create_base_magic_box_fx(); + level thread handle_fire_sale(); +} + +custom_joker_movement() +{ + v_origin = self.weapon_model.origin - vectorScale( ( 0, 1, 0 ), 5 ); + self.weapon_model delete(); + m_lock = spawn( "script_model", v_origin ); + m_lock setmodel( level.chest_joker_model ); + m_lock.angles = self.angles + vectorScale( ( 0, 1, 0 ), 180 ); + wait 0,5; + level notify( "weapon_fly_away_start" ); + wait 1; + m_lock rotateyaw( 3000, 4, 4 ); + wait 3; + m_lock movez( 20, 0,5, 0,5 ); + m_lock waittill( "movedone" ); + m_lock movez( -100, 0,5, 0,5 ); + m_lock waittill( "movedone" ); + m_lock delete(); + self notify( "box_moving" ); + level notify( "weapon_fly_away_end" ); +} + +wait_then_create_base_magic_box_fx() +{ + while ( !isDefined( level.chests ) ) + { + wait 0,5; + } + while ( !isDefined( level.chests[ level.chests.size - 1 ].zbarrier ) ) + { + wait 0,5; + } + _a92 = level.chests; + _k92 = getFirstArrayKey( _a92 ); + while ( isDefined( _k92 ) ) + { + chest = _a92[ _k92 ]; + chest.zbarrier setclientfield( "magicbox_initial_fx", 1 ); + _k92 = getNextArrayKey( _a92, _k92 ); + } +} + +set_magic_box_zbarrier_state( state ) +{ + i = 0; + while ( i < self getnumzbarrierpieces() ) + { + self hidezbarrierpiece( i ); + i++; + } + self notify( "zbarrier_state_change" ); + switch( state ) + { + case "away": + self showzbarrierpiece( 0 ); + self.state = "away"; + self.owner.is_locked = 0; + break; + case "arriving": + self showzbarrierpiece( 1 ); + self thread magic_box_arrives(); + self.state = "arriving"; + break; + case "initial": + self showzbarrierpiece( 1 ); + self thread magic_box_initial(); + thread maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( self.owner.unitrigger_stub, ::maps/mp/zombies/_zm_magicbox::magicbox_unitrigger_think ); + self.state = "close"; + break; + case "open": + self showzbarrierpiece( 2 ); + self thread magic_box_opens(); + self.state = "open"; + break; + case "close": + self showzbarrierpiece( 2 ); + self thread magic_box_closes(); + self.state = "close"; + break; + case "leaving": + self showzbarrierpiece( 1 ); + self thread magic_box_leaves(); + self.state = "leaving"; + self.owner.is_locked = 0; + break; + default: + if ( isDefined( level.custom_magicbox_state_handler ) ) + { + self [[ level.custom_magicbox_state_handler ]]( state ); + } + break; + } +} + +magic_box_initial() +{ + self setzbarrierpiecestate( 1, "open" ); + wait 1; + self setclientfield( "magicbox_amb_fx", 1 ); +} + +magic_box_arrives() +{ + self setclientfield( "magicbox_leaving_fx", 0 ); + self setclientfield( "magicbox_amb_fx", 1 ); + self setzbarrierpiecestate( 1, "opening" ); + while ( self getzbarrierpiecestate( 1 ) == "opening" ) + { + wait 0,05; + } + self notify( "arrived" ); + self.state = "close"; +} + +magic_box_leaves() +{ + self setclientfield( "magicbox_leaving_fx", 1 ); + self setclientfield( "magicbox_open_fx", 0 ); + self setzbarrierpiecestate( 1, "closing" ); + self playsound( "zmb_hellbox_rise" ); + while ( self getzbarrierpiecestate( 1 ) == "closing" ) + { + wait 0,1; + } + self notify( "left" ); + self setclientfield( "magicbox_amb_fx", 0 ); +} + +magic_box_opens() +{ + self setclientfield( "magicbox_open_fx", 1 ); + self setzbarrierpiecestate( 2, "opening" ); + self playsound( "zmb_hellbox_open" ); + while ( self getzbarrierpiecestate( 2 ) == "opening" ) + { + wait 0,1; + } + self notify( "opened" ); +} + +magic_box_closes() +{ + self setzbarrierpiecestate( 2, "closing" ); + self playsound( "zmb_hellbox_close" ); + while ( self getzbarrierpiecestate( 2 ) == "closing" ) + { + wait 0,1; + } + self notify( "closed" ); + self setclientfield( "magicbox_open_fx", 0 ); +} + +magic_box_do_weapon_rise() +{ + self endon( "box_hacked_respin" ); + self setzbarrierpiecestate( 3, "closed" ); + self setzbarrierpiecestate( 4, "closed" ); + wait_network_frame(); + self zbarrierpieceuseboxriselogic( 3 ); + self zbarrierpieceuseboxriselogic( 4 ); + self showzbarrierpiece( 3 ); + self showzbarrierpiece( 4 ); + self setzbarrierpiecestate( 3, "opening" ); + self setzbarrierpiecestate( 4, "opening" ); + while ( self getzbarrierpiecestate( 3 ) != "open" ) + { + wait 0,5; + } + self hidezbarrierpiece( 3 ); + self hidezbarrierpiece( 4 ); +} + +handle_fire_sale() +{ + while ( 1 ) + { + level waittill( "fire_sale_off" ); + i = 0; + while ( i < level.chests.size ) + { + if ( level.chest_index != i && isDefined( level.chests[ i ].was_temp ) ) + { + level.chests[ i ].zbarrier setclientfield( "magicbox_amb_fx", 0 ); + } + i++; + } + } +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_melee_weapon.gsc b/zm_prison_patch/maps/mp/zombies/_zm_melee_weapon.gsc new file mode 100644 index 0000000..fc1ef72 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_melee_weapon.gsc @@ -0,0 +1,556 @@ +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init( weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, has_weapon, give_weapon, take_weapon, flourish_fn ) +{ + precacheitem( weapon_name ); + precacheitem( flourish_weapon_name ); + add_melee_weapon( weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, has_weapon, give_weapon, take_weapon ); + melee_weapon_triggers = getentarray( wallbuy_targetname, "targetname" ); + i = 0; + while ( i < melee_weapon_triggers.size ) + { + knife_model = getent( melee_weapon_triggers[ i ].target, "targetname" ); + if ( isDefined( knife_model ) ) + { + knife_model hide(); + } + melee_weapon_triggers[ i ] thread melee_weapon_think( weapon_name, cost, has_weapon, give_weapon, flourish_fn, vo_dialog_id, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name ); + melee_weapon_triggers[ i ] sethintstring( hint_string, cost ); + melee_weapon_triggers[ i ] setcursorhint( "HINT_NOICON" ); + melee_weapon_triggers[ i ] usetriggerrequirelookat(); + i++; + } + melee_weapon_structs = getstructarray( wallbuy_targetname, "targetname" ); + i = 0; + while ( i < melee_weapon_structs.size ) + { + prepare_stub( melee_weapon_structs[ i ].trigger_stub, weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, has_weapon, give_weapon, take_weapon, flourish_fn ); + i++; + } + register_melee_weapon_for_level( weapon_name ); + if ( !isDefined( level.ballistic_weapon_name ) ) + { + level.ballistic_weapon_name = []; + } + level.ballistic_weapon_name[ weapon_name ] = ballistic_weapon_name; + if ( !isDefined( level.ballistic_upgraded_weapon_name ) ) + { + level.ballistic_upgraded_weapon_name = []; + } + level.ballistic_upgraded_weapon_name[ weapon_name ] = ballistic_upgraded_weapon_name; +} + +prepare_stub( stub, weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, has_weapon, give_weapon, take_weapon, flourish_fn ) +{ + if ( isDefined( stub ) ) + { + stub.hint_string = hint_string; + stub.cost = cost; + stub.weapon_name = weapon_name; + stub.has_weapon = has_weapon; + stub.give_weapon = give_weapon; + stub.take_weapon = take_weapon; + stub.vo_dialog_id = vo_dialog_id; + stub.flourish_weapon_name = flourish_weapon_name; + stub.ballistic_weapon_name = ballistic_weapon_name; + stub.ballistic_upgraded_weapon_name = ballistic_upgraded_weapon_name; + stub.trigger_func = ::melee_weapon_think; + stub.flourish_fn = flourish_fn; + } +} + +add_stub( stub, weapon_name ) +{ + melee_weapon = undefined; + i = 0; + while ( i < level._melee_weapons.size ) + { + if ( level._melee_weapons[ i ].weapon_name == weapon_name ) + { + melee_weapon = level._melee_weapons[ i ]; + break; + } + else + { + i++; + } + } + if ( isDefined( stub ) && isDefined( melee_weapon ) ) + { + prepare_stub( stub, melee_weapon.weapon_name, melee_weapon.flourish_weapon_name, melee_weapon.ballistic_weapon_name, melee_weapon.ballistic_upgraded_weapon_name, melee_weapon.cost, melee_weapon.wallbuy_targetname, melee_weapon.hint_string, melee_weapon.vo_dialog_id, melee_weapon.has_weapon, melee_weapon.give_weapon, melee_weapon.take_weapon, melee_weapon.flourish_fn ); + } +} + +give_melee_weapon_by_name( weapon_name ) +{ + melee_weapon = undefined; + i = 0; + while ( i < level._melee_weapons.size ) + { + if ( level._melee_weapons[ i ].weapon_name == weapon_name ) + { + melee_weapon = level._melee_weapons[ i ]; + break; + } + else + { + i++; + } + } + if ( isDefined( melee_weapon ) ) + { + self thread give_melee_weapon( melee_weapon.vo_dialog_id, melee_weapon.flourish_weapon_name, melee_weapon.weapon_name, melee_weapon.ballistic_weapon_name, melee_weapon.ballistic_upgraded_weapon_name, melee_weapon.give_weapon, melee_weapon.flourish_fn, undefined ); + } +} + +add_melee_weapon( weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, has_weapon, give_weapon, take_weapon, flourish_fn ) +{ + melee_weapon = spawnstruct(); + melee_weapon.weapon_name = weapon_name; + melee_weapon.flourish_weapon_name = flourish_weapon_name; + melee_weapon.ballistic_weapon_name = ballistic_weapon_name; + melee_weapon.ballistic_upgraded_weapon_name = ballistic_upgraded_weapon_name; + melee_weapon.cost = cost; + melee_weapon.wallbuy_targetname = wallbuy_targetname; + melee_weapon.hint_string = hint_string; + melee_weapon.vo_dialog_id = vo_dialog_id; + melee_weapon.has_weapon = has_weapon; + melee_weapon.give_weapon = give_weapon; + melee_weapon.take_weapon = take_weapon; + melee_weapon.flourish_fn = flourish_fn; + if ( !isDefined( level._melee_weapons ) ) + { + level._melee_weapons = []; + } + level._melee_weapons[ level._melee_weapons.size ] = melee_weapon; +} + +spectator_respawn_all() +{ + i = 0; + while ( i < level._melee_weapons.size ) + { + self [[ level._melee_weapons[ i ].take_weapon ]](); + i++; + } + i = 0; + while ( i < level._melee_weapons.size ) + { + self spectator_respawn( level._melee_weapons[ i ].wallbuy_targetname, level._melee_weapons[ i ].take_weapon, level._melee_weapons[ i ].has_weapon ); + i++; + } +} + +spectator_respawn( wallbuy_targetname, take_weapon, has_weapon ) +{ + melee_triggers = getentarray( wallbuy_targetname, "targetname" ); + players = get_players(); + i = 0; + while ( i < melee_triggers.size ) + { + melee_triggers[ i ] setvisibletoall(); + while ( isDefined( level._allow_melee_weapon_switching ) && !level._allow_melee_weapon_switching ) + { + j = 0; + while ( j < players.size ) + { + if ( players[ j ] [[ has_weapon ]]() ) + { + melee_triggers[ i ] setinvisibletoplayer( players[ j ] ); + } + j++; + } + } + i++; + } +} + +trigger_hide_all() +{ + i = 0; + while ( i < level._melee_weapons.size ) + { + self trigger_hide( level._melee_weapons[ i ].wallbuy_targetname ); + i++; + } +} + +trigger_hide( wallbuy_targetname ) +{ + melee_triggers = getentarray( wallbuy_targetname, "targetname" ); + i = 0; + while ( i < melee_triggers.size ) + { + melee_triggers[ i ] setinvisibletoplayer( self ); + i++; + } +} + +has_any_ballistic_knife() +{ + if ( self hasweapon( "knife_ballistic_zm" ) ) + { + return 1; + } + if ( self hasweapon( "knife_ballistic_upgraded_zm" ) ) + { + return 1; + } + i = 0; + while ( i < level._melee_weapons.size ) + { + if ( self hasweapon( level._melee_weapons[ i ].ballistic_weapon_name ) ) + { + return 1; + } + if ( self hasweapon( level._melee_weapons[ i ].ballistic_upgraded_weapon_name ) ) + { + return 1; + } + i++; + } + return 0; +} + +has_upgraded_ballistic_knife() +{ + if ( self hasweapon( "knife_ballistic_upgraded_zm" ) ) + { + return 1; + } + i = 0; + while ( i < level._melee_weapons.size ) + { + if ( self hasweapon( level._melee_weapons[ i ].ballistic_upgraded_weapon_name ) ) + { + return 1; + } + i++; + } + return 0; +} + +give_ballistic_knife( weapon_string, upgraded ) +{ + current_melee_weapon = self get_player_melee_weapon(); + if ( isDefined( current_melee_weapon ) ) + { + if ( upgraded && isDefined( level.ballistic_upgraded_weapon_name ) && isDefined( level.ballistic_upgraded_weapon_name[ current_melee_weapon ] ) ) + { + weapon_string = level.ballistic_upgraded_weapon_name[ current_melee_weapon ]; + } + if ( !upgraded && isDefined( level.ballistic_weapon_name ) && isDefined( level.ballistic_weapon_name[ current_melee_weapon ] ) ) + { + weapon_string = level.ballistic_weapon_name[ current_melee_weapon ]; + } + } + return weapon_string; +} + +change_melee_weapon( weapon_name, current_weapon ) +{ + current_melee_weapon = self get_player_melee_weapon(); + if ( isDefined( current_melee_weapon ) ) + { + self takeweapon( current_melee_weapon ); + unacquire_weapon_toggle( current_melee_weapon ); + } + self set_player_melee_weapon( weapon_name ); + had_ballistic = 0; + had_ballistic_upgraded = 0; + ballistic_was_primary = 0; + primaryweapons = self getweaponslistprimaries(); + i = 0; + while ( i < primaryweapons.size ) + { + primary_weapon = primaryweapons[ i ]; + if ( issubstr( primary_weapon, "knife_ballistic_" ) ) + { + had_ballistic = 1; + if ( primary_weapon == current_weapon ) + { + ballistic_was_primary = 1; + } + self notify( "zmb_lost_knife" ); + self takeweapon( primary_weapon ); + unacquire_weapon_toggle( primary_weapon ); + if ( issubstr( primary_weapon, "upgraded" ) ) + { + had_ballistic_upgraded = 1; + } + } + i++; + } + if ( had_ballistic ) + { + if ( had_ballistic_upgraded ) + { + new_ballistic = level.ballistic_upgraded_weapon_name[ weapon_name ]; + if ( ballistic_was_primary ) + { + current_weapon = new_ballistic; + } + self giveweapon( new_ballistic, 0, self maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( new_ballistic ) ); + } + else + { + new_ballistic = level.ballistic_weapon_name[ weapon_name ]; + if ( ballistic_was_primary ) + { + current_weapon = new_ballistic; + } + self giveweapon( new_ballistic, 0 ); + } + } + return current_weapon; +} + +melee_weapon_think( weapon_name, cost, has_weapon, give_weapon, flourish_fn, vo_dialog_id, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name ) +{ + self.first_time_triggered = 0; + while ( isDefined( self.stub ) ) + { + self endon( "kill_trigger" ); + if ( isDefined( self.stub.first_time_triggered ) ) + { + self.first_time_triggered = self.stub.first_time_triggered; + } + weapon_name = self.stub.weapon_name; + cost = self.stub.cost; + has_weapon = self.stub.has_weapon; + give_weapon = self.stub.give_weapon; + flourish_fn = self.stub.flourish_fn; + vo_dialog_id = self.stub.vo_dialog_id; + flourish_weapon_name = self.stub.flourish_weapon_name; + ballistic_weapon_name = self.stub.ballistic_weapon_name; + ballistic_upgraded_weapon_name = self.stub.ballistic_upgraded_weapon_name; + players = getplayers(); + while ( isDefined( level._allow_melee_weapon_switching ) && !level._allow_melee_weapon_switching ) + { + i = 0; + while ( i < players.size ) + { + if ( players[ i ] [[ has_weapon ]]() ) + { + self setinvisibletoplayer( players[ i ] ); + } + i++; + } + } + } + for ( ;; ) + { + self waittill( "trigger", player ); + if ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + continue; + } + else if ( player in_revive_trigger() ) + { + wait 0,1; + continue; + } + else if ( player isthrowinggrenade() ) + { + wait 0,1; + continue; + } + else if ( player.is_drinking > 0 ) + { + wait 0,1; + continue; + } + else if ( player hasweapon( weapon_name ) || player has_powerup_weapon() ) + { + wait 0,1; + continue; + } + else + { + if ( player isswitchingweapons() ) + { + wait 0,1; + break; + } + else current_weapon = player getcurrentweapon(); + if ( !is_placeable_mine( current_weapon ) || is_equipment( current_weapon ) && player has_powerup_weapon() ) + { + wait 0,1; + break; + } + else + { + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() || isDefined( player.intermission ) && player.intermission ) + { + wait 0,1; + break; + } + else + { + player_has_weapon = player [[ has_weapon ]](); + if ( !player_has_weapon ) + { + if ( player.score >= cost ) + { + if ( self.first_time_triggered == 0 ) + { + model = getent( self.target, "targetname" ); + if ( isDefined( model ) ) + { + model thread melee_weapon_show( player ); + } + else + { + if ( isDefined( self.clientfieldname ) ) + { + level setclientfield( self.clientfieldname, 1 ); + } + } + self.first_time_triggered = 1; + if ( isDefined( self.stub ) ) + { + self.stub.first_time_triggered = 1; + } + } + player maps/mp/zombies/_zm_score::minus_to_player_score( cost ); + bbprint( "zombie_uses", "playername %s playerscore %d round %d cost %d name %s x %f y %f z %f type %s", player.name, player.score, level.round_number, cost, weapon_name, self.origin, "weapon" ); + player thread give_melee_weapon( vo_dialog_id, flourish_weapon_name, weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, give_weapon, flourish_fn, self ); + } + else + { + play_sound_on_ent( "no_purchase" ); + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "no_money_weapon", undefined, 1 ); + } + break; + } + else + { + if ( isDefined( level._allow_melee_weapon_switching ) && !level._allow_melee_weapon_switching ) + { + self setinvisibletoplayer( player ); + } + } + } + } + } + } +} + +melee_weapon_show( player ) +{ + player_angles = vectorToAngle( player.origin - self.origin ); + player_yaw = player_angles[ 1 ]; + weapon_yaw = self.angles[ 1 ]; + yaw_diff = angleClamp180( player_yaw - weapon_yaw ); + if ( yaw_diff > 0 ) + { + yaw = weapon_yaw - 90; + } + else + { + yaw = weapon_yaw + 90; + } + self.og_origin = self.origin; + self.origin += anglesToForward( ( 0, yaw, 0 ) ) * 8; + wait 0,05; + self show(); + play_sound_at_pos( "weapon_show", self.origin, self ); + time = 1; + self moveto( self.og_origin, time ); +} + +give_melee_weapon( vo_dialog_id, flourish_weapon_name, weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, give_weapon, flourish_fn, trigger ) +{ + if ( isDefined( flourish_fn ) ) + { + self thread [[ flourish_fn ]](); + } + gun = self do_melee_weapon_flourish_begin( flourish_weapon_name ); + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", vo_dialog_id ); + self waittill_any( "fake_death", "death", "player_downed", "weapon_change_complete" ); + self do_melee_weapon_flourish_end( gun, flourish_weapon_name, weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name ); + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || isDefined( self.intermission ) && self.intermission ) + { + return; + } + self [[ give_weapon ]](); + if ( isDefined( level._allow_melee_weapon_switching ) && !level._allow_melee_weapon_switching ) + { + if ( isDefined( trigger ) ) + { + trigger setinvisibletoplayer( self ); + } + self trigger_hide_all(); + } +} + +do_melee_weapon_flourish_begin( flourish_weapon_name ) +{ + self increment_is_drinking(); + self disable_player_move_states( 1 ); + gun = self getcurrentweapon(); + weapon = flourish_weapon_name; + self giveweapon( weapon ); + self switchtoweapon( weapon ); + return gun; +} + +do_melee_weapon_flourish_end( gun, flourish_weapon_name, weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name ) +{ +/# + assert( !is_zombie_perk_bottle( gun ) ); +#/ +/# + assert( gun != level.revive_tool ); +#/ + self enable_player_move_states(); + weapon = flourish_weapon_name; + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || isDefined( self.intermission ) && self.intermission ) + { + self takeweapon( weapon ); + self.lastactiveweapon = "none"; + return; + } + self takeweapon( weapon ); + self giveweapon( weapon_name ); + gun = change_melee_weapon( weapon_name, gun ); + if ( self hasweapon( "knife_zm" ) ) + { + self takeweapon( "knife_zm" ); + } + if ( self is_multiple_drinking() ) + { + self decrement_is_drinking(); + return; + } + else if ( gun == "knife_zm" ) + { + self switchtoweapon( weapon_name ); + self decrement_is_drinking(); + return; + } + else if ( gun != "none" && !is_placeable_mine( gun ) && !is_equipment( gun ) ) + { + self switchtoweapon( gun ); + } + else + { + primaryweapons = self getweaponslistprimaries(); + if ( isDefined( primaryweapons ) && primaryweapons.size > 0 ) + { + self switchtoweapon( primaryweapons[ 0 ] ); + } + } + self waittill( "weapon_change_complete" ); + if ( !self maps/mp/zombies/_zm_laststand::player_is_in_laststand() && isDefined( self.intermission ) && !self.intermission ) + { + self decrement_is_drinking(); + } +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_perk_electric_cherry.gsc b/zm_prison_patch/maps/mp/zombies/_zm_perk_electric_cherry.gsc new file mode 100644 index 0000000..6c32c17 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_perk_electric_cherry.gsc @@ -0,0 +1,391 @@ +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/animscripts/shared; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_perks; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +enable_electric_cherry_perk_for_level() +{ + maps/mp/zombies/_zm_perks::register_perk_basic_info( "specialty_grenadepulldeath", "electric_cherry", 2000, &"ZM_PRISON_PERK_CHERRY", "zombie_perk_bottle_cherry" ); + maps/mp/zombies/_zm_perks::register_perk_precache_func( "specialty_grenadepulldeath", ::electic_cherry_precache ); + maps/mp/zombies/_zm_perks::register_perk_clientfields( "specialty_grenadepulldeath", ::electric_cherry_register_clientfield, ::electric_cherry_set_clientfield ); + maps/mp/zombies/_zm_perks::register_perk_threads( "specialty_grenadepulldeath", ::electric_cherry_reload_attack, ::electric_cherry_perk_lost ); + maps/mp/zombies/_zm_perks::register_perk_machine( "specialty_grenadepulldeath", ::electric_cherry_perk_machine_setup, ::electric_cherry_perk_machine_think ); + maps/mp/zombies/_zm_perks::register_perk_host_migration_func( "specialty_grenadepulldeath", ::electric_cherry_host_migration_func ); +} + +init_electric_cherry() +{ + level.custom_laststand_func = ::electric_cherry_laststand; + set_zombie_var( "tesla_head_gib_chance", 50 ); + registerclientfield( "allplayers", "electric_cherry_reload_fx", 9000, 2, "int" ); +} + +electic_cherry_precache() +{ + precacheitem( "zombie_perk_bottle_cherry" ); + precacheshader( "specialty_fastreload_zombies" ); + precachemodel( "p6_zm_vending_electric_cherry_off" ); + precachemodel( "p6_zm_vending_electric_cherry_on" ); + precachestring( &"ZM_PRISON_PERK_CHERRY" ); + level._effect[ "electriccherry" ] = loadfx( "misc/fx_zombie_cola_on" ); + level._effect[ "electric_cherry_explode" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_electric_cherry_down" ); + level._effect[ "electric_cherry_reload_small" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_electric_cherry_sm" ); + level._effect[ "electric_cherry_reload_medium" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_electric_cherry_player" ); + level._effect[ "electric_cherry_reload_large" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_electric_cherry_lg" ); + level._effect[ "tesla_shock" ] = loadfx( "maps/zombie/fx_zombie_tesla_shock" ); + level._effect[ "tesla_shock_secondary" ] = loadfx( "maps/zombie/fx_zombie_tesla_shock_secondary" ); +} + +electric_cherry_register_clientfield() +{ + registerclientfield( "toplayer", "perk_electric_cherry", 9000, 1, "int" ); +} + +electric_cherry_set_clientfield( state ) +{ + self setclientfieldtoplayer( "perk_electric_cherry", state ); +} + +electric_cherry_perk_machine_setup( use_trigger, perk_machine, bump_trigger, collision ) +{ + use_trigger.script_sound = "mus_perks_cherry_jingle"; + use_trigger.script_string = "electric_cherry_perk"; + use_trigger.script_label = "mus_perks_cherry_sting"; + use_trigger.target = "vending_electriccherry"; + perk_machine.script_string = "electriccherry_perk"; + perk_machine.targetname = "vendingelectric_cherry"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "electriccherry_perk"; + } +} + +electric_cherry_perk_machine_think() +{ + init_electric_cherry(); + while ( 1 ) + { + machine = getentarray( "vendingelectric_cherry", "targetname" ); + machine_triggers = getentarray( "vending_electriccherry", "target" ); + i = 0; + while ( i < machine.size ) + { + machine[ i ] setmodel( "p6_zm_vending_electric_cherry_off" ); + i++; + } + level thread do_initial_power_off_callback( machine, "electriccherry" ); + array_thread( machine_triggers, ::maps/mp/zombies/_zm_perks::set_power_on, 0 ); + level waittill( "electric_cherry_on" ); + i = 0; + while ( i < machine.size ) + { + machine[ i ] setmodel( "p6_zm_vending_electric_cherry_on" ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0,3, 0,4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "electriccherry" ); + machine[ i ] thread play_loop_on_machine(); + i++; + } + level notify( "specialty_grenadepulldeath_power_on" ); + array_thread( machine_triggers, ::maps/mp/zombies/_zm_perks::set_power_on, 1 ); + level waittill( "electric_cherry_off" ); + array_thread( machine, ::maps/mp/zombies/_zm_perks::turn_perk_off ); + } +} + +electric_cherry_host_migration_func() +{ + a_electric_cherry_perk_machines = getentarray( "vending_electriccherry", "targetname" ); + _a125 = a_electric_cherry_perk_machines; + _k125 = getFirstArrayKey( _a125 ); + while ( isDefined( _k125 ) ) + { + perk_machine = _a125[ _k125 ]; + if ( isDefined( perk_machine.model ) && perk_machine.model == "p6_zm_vending_electric_cherry_on" ) + { + perk_machine perk_fx( undefined, 1 ); + perk_machine thread perk_fx( "electriccherry" ); + } + _k125 = getNextArrayKey( _a125, _k125 ); + } +} + +electric_cherry_laststand() +{ + visionsetlaststand( "zombie_last_stand", 1 ); + if ( isDefined( self ) ) + { + playfx( level._effect[ "electric_cherry_explode" ], self.origin ); + self playsound( "zmb_cherry_explode" ); + self notify( "electric_cherry_start" ); + wait 0,05; + a_zombies = get_round_enemy_array(); + a_zombies = get_array_of_closest( self.origin, a_zombies, undefined, undefined, 500 ); + i = 0; + while ( i < a_zombies.size ) + { + if ( isalive( self ) ) + { + if ( a_zombies[ i ].health <= 1000 ) + { + a_zombies[ i ] thread electric_cherry_death_fx(); + if ( isDefined( self.cherry_kills ) ) + { + self.cherry_kills++; + } + self maps/mp/zombies/_zm_score::add_to_player_score( 40 ); + } + else + { + a_zombies[ i ] thread electric_cherry_stun(); + a_zombies[ i ] thread electric_cherry_shock_fx(); + } + wait 0,1; + a_zombies[ i ] dodamage( 1000, self.origin, self, self, "none" ); + } + i++; + } + self notify( "electric_cherry_end" ); + } +} + +electric_cherry_death_fx() +{ + self endon( "death" ); + tag = "J_SpineUpper"; + fx = "tesla_shock"; + if ( self.isdog ) + { + tag = "J_Spine1"; + } + self playsound( "zmb_elec_jib_zombie" ); + network_safe_play_fx_on_tag( "tesla_death_fx", 2, level._effect[ fx ], self, tag ); + if ( isDefined( self.tesla_head_gib_func ) && !self.head_gibbed ) + { + [[ self.tesla_head_gib_func ]](); + } +} + +electric_cherry_shock_fx() +{ + self endon( "death" ); + tag = "J_SpineUpper"; + fx = "tesla_shock_secondary"; + if ( self.isdog ) + { + tag = "J_Spine1"; + } + self playsound( "zmb_elec_jib_zombie" ); + network_safe_play_fx_on_tag( "tesla_shock_fx", 2, level._effect[ fx ], self, tag ); +} + +electric_cherry_stun() +{ + self endon( "death" ); + self notify( "stun_zombie" ); + self endon( "stun_zombie" ); + if ( self.health <= 0 ) + { +/# + iprintln( "trying to stun a dead zombie" ); +#/ + return; + } + if ( self.ai_state != "find_flesh" ) + { + return; + } + self.forcemovementscriptstate = 1; + self.ignoreall = 1; + i = 0; + while ( i < 2 ) + { + self animscripted( self.origin, self.angles, "zm_afterlife_stun" ); + self maps/mp/animscripts/shared::donotetracks( "stunned" ); + i++; + } + self.forcemovementscriptstate = 0; + self.ignoreall = 0; + self setgoalpos( self.origin ); + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); +} + +electric_cherry_reload_attack() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "stop_electric_cherry_reload_attack" ); + self.wait_on_reload = []; + self.consecutive_electric_cherry_attacks = 0; + while ( 1 ) + { + self waittill( "reload_start" ); + str_current_weapon = self getcurrentweapon(); + while ( isinarray( self.wait_on_reload, str_current_weapon ) ) + { + continue; + } + self.wait_on_reload[ self.wait_on_reload.size ] = str_current_weapon; + self.consecutive_electric_cherry_attacks++; + n_clip_current = self getweaponammoclip( str_current_weapon ); + n_clip_max = weaponclipsize( str_current_weapon ); + n_fraction = n_clip_current / n_clip_max; + perk_radius = linear_map( n_fraction, 1, 0, 32, 128 ); + perk_dmg = linear_map( n_fraction, 1, 0, 1, 1045 ); + self thread check_for_reload_complete( str_current_weapon ); + if ( isDefined( self ) ) + { + switch( self.consecutive_electric_cherry_attacks ) + { + case 0: + case 1: + n_zombie_limit = undefined; + break; + case 2: + n_zombie_limit = 8; + break; + case 3: + n_zombie_limit = 4; + break; + case 4: + n_zombie_limit = 2; + break; + default: + n_zombie_limit = 0; + } + self thread electric_cherry_cooldown_timer( str_current_weapon ); + if ( isDefined( n_zombie_limit ) && n_zombie_limit == 0 ) + { + continue; + } + self thread electric_cherry_reload_fx( n_fraction ); + self notify( "electric_cherry_start" ); + self playsound( "zmb_cherry_explode" ); + a_zombies = get_round_enemy_array(); + a_zombies = get_array_of_closest( self.origin, a_zombies, undefined, undefined, perk_radius ); + n_zombies_hit = 0; + i = 0; + while ( i < a_zombies.size ) + { + if ( isalive( self ) ) + { + if ( isDefined( n_zombie_limit ) ) + { + if ( n_zombies_hit < n_zombie_limit ) + { + n_zombies_hit++; + break; + } + else } + else if ( a_zombies[ i ].health <= perk_dmg ) + { + a_zombies[ i ] thread electric_cherry_death_fx(); + if ( isDefined( self.cherry_kills ) ) + { + self.cherry_kills++; + } + self maps/mp/zombies/_zm_score::add_to_player_score( 40 ); + } + else + { + if ( !isDefined( a_zombies[ i ].is_brutus ) ) + { + a_zombies[ i ] thread electric_cherry_stun(); + } + a_zombies[ i ] thread electric_cherry_shock_fx(); + } + wait 0,1; + a_zombies[ i ] dodamage( perk_dmg, self.origin, self, self, "none" ); + } + i++; + } + self notify( "electric_cherry_end" ); + } + } +} + +electric_cherry_cooldown_timer( str_current_weapon ) +{ + self notify( "electric_cherry_cooldown_started" ); + self endon( "electric_cherry_cooldown_started" ); + self endon( "death" ); + self endon( "disconnect" ); + n_reload_time = weaponreloadtime( str_current_weapon ); + if ( self hasperk( "specialty_fastreload" ) ) + { + n_reload_time *= getDvarFloat( "perk_weapReloadMultiplier" ); + } + n_cooldown_time = n_reload_time + 3; + wait n_cooldown_time; + self.consecutive_electric_cherry_attacks = 0; +} + +check_for_reload_complete( weapon ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "player_lost_weapon_" + weapon ); + self thread weapon_replaced_monitor( weapon ); + while ( 1 ) + { + self waittill( "reload" ); + str_current_weapon = self getcurrentweapon(); + if ( str_current_weapon == weapon ) + { + arrayremovevalue( self.wait_on_reload, weapon ); + self notify( "weapon_reload_complete_" + weapon ); + return; + } + else + { + } + } +} + +weapon_replaced_monitor( weapon ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "weapon_reload_complete_" + weapon ); + while ( 1 ) + { + self waittill( "weapon_change" ); + primaryweapons = self getweaponslistprimaries(); + if ( !isinarray( primaryweapons, weapon ) ) + { + self notify( "player_lost_weapon_" + weapon ); + arrayremovevalue( self.wait_on_reload, weapon ); + return; + } + else + { + } + } +} + +electric_cherry_reload_fx( n_fraction ) +{ + if ( n_fraction >= 0,67 ) + { + self setclientfield( "electric_cherry_reload_fx", 1 ); + } + else if ( n_fraction >= 0,33 && n_fraction < 0,67 ) + { + self setclientfield( "electric_cherry_reload_fx", 2 ); + } + else + { + self setclientfield( "electric_cherry_reload_fx", 3 ); + } + wait 1; + self setclientfield( "electric_cherry_reload_fx", 0 ); +} + +electric_cherry_perk_lost() +{ + self notify( "stop_electric_cherry_reload_attack" ); +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_riotshield_prison.gsc b/zm_prison_patch/maps/mp/zombies/_zm_riotshield_prison.gsc new file mode 100644 index 0000000..83a23fd --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_riotshield_prison.gsc @@ -0,0 +1,670 @@ +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_buildables; +#include maps/mp/zombies/_zm_weap_riotshield_prison; +#include common_scripts/utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; + +init() +{ + level.riotshield_name = "alcatraz_shield_zm"; + level.deployedshieldmodel = []; + level.stowedshieldmodel = []; + level.carriedshieldmodel = []; + level.deployedshieldmodel[ 0 ] = "t6_wpn_zmb_shield_dlc2_dmg0_world"; + level.deployedshieldmodel[ 2 ] = "t6_wpn_zmb_shield_dlc2_dmg1_world"; + level.deployedshieldmodel[ 3 ] = "t6_wpn_zmb_shield_dlc2_dmg2_world"; + level.stowedshieldmodel[ 0 ] = "t6_wpn_zmb_shield_dlc2_dmg0_stow"; + level.stowedshieldmodel[ 2 ] = "t6_wpn_zmb_shield_dlc2_dmg1_stow"; + level.stowedshieldmodel[ 3 ] = "t6_wpn_zmb_shield_dlc2_dmg2_stow"; + level.carriedshieldmodel[ 0 ] = "t6_wpn_zmb_shield_dlc2_dmg0_world"; + level.carriedshieldmodel[ 2 ] = "t6_wpn_zmb_shield_dlc2_dmg1_world"; + level.carriedshieldmodel[ 3 ] = "t6_wpn_zmb_shield_dlc2_dmg2_world"; + level.viewshieldmodel[ 0 ] = "t6_wpn_zmb_shield_dlc2_dmg0_view"; + level.viewshieldmodel[ 2 ] = "t6_wpn_zmb_shield_dlc2_dmg1_view"; + level.viewshieldmodel[ 3 ] = "t6_wpn_zmb_shield_dlc2_dmg2_view"; + precachemodel( level.stowedshieldmodel[ 0 ] ); + precachemodel( level.stowedshieldmodel[ 2 ] ); + precachemodel( level.stowedshieldmodel[ 3 ] ); + precachemodel( level.carriedshieldmodel[ 0 ] ); + precachemodel( level.carriedshieldmodel[ 2 ] ); + precachemodel( level.carriedshieldmodel[ 3 ] ); + precachemodel( level.viewshieldmodel[ 0 ] ); + precachemodel( level.viewshieldmodel[ 2 ] ); + precachemodel( level.viewshieldmodel[ 3 ] ); + level.riotshield_placement_zoffset = 26; +} + +attachriotshield( model, tag ) +{ + if ( isDefined( self.prev_shield_model ) && isDefined( self.prev_shield_tag ) ) + { + self detachshieldmodel( self.prev_shield_model, self.prev_shield_tag ); + } + self.prev_shield_model = model; + self.prev_shield_tag = tag; + if ( isDefined( self.prev_shield_model ) && isDefined( self.prev_shield_tag ) ) + { + self attachshieldmodel( self.prev_shield_model, self.prev_shield_tag ); + } +} + +removeriotshield() +{ + if ( isDefined( self.prev_shield_model ) && isDefined( self.prev_shield_tag ) ) + { + self detachshieldmodel( self.prev_shield_model, self.prev_shield_tag ); + } + self.prev_shield_model = undefined; + self.prev_shield_tag = undefined; + if ( self getcurrentweapon() != level.riotshield_name ) + { + return; + } + self setheldweaponmodel( 0 ); +} + +setriotshieldviewmodel( modelnum ) +{ + self.prev_shield_viewmodel = modelnum; + if ( self getcurrentweapon() != level.riotshield_name ) + { + return; + } + if ( isDefined( self.prev_shield_viewmodel ) ) + { + self setheldweaponmodel( self.prev_shield_viewmodel ); + } + else + { + self setheldweaponmodel( 0 ); + } +} + +specialriotshieldviewmodel() +{ + if ( self getcurrentweapon() != level.riotshield_name ) + { + return; + } + self setheldweaponmodel( 3 ); +} + +restoreriotshieldviewmodel() +{ + if ( self getcurrentweapon() != level.riotshield_name ) + { + return; + } + if ( isDefined( self.prev_shield_viewmodel ) ) + { + self setheldweaponmodel( self.prev_shield_viewmodel ); + } + else + { + self setheldweaponmodel( 0 ); + } +} + +updateriotshieldmodel() +{ + if ( !isDefined( self.shield_damage_level ) ) + { + if ( isDefined( self.player_shield_reset_health ) ) + { + self [[ self.player_shield_reset_health ]](); + } + } + update = 0; + if ( !isDefined( self.prev_shield_damage_level ) || self.prev_shield_damage_level != self.shield_damage_level ) + { + self.prev_shield_damage_level = self.shield_damage_level; + update = 1; + } + if ( !isDefined( self.prev_shield_placement ) || self.prev_shield_placement != self.shield_placement ) + { + self.prev_shield_placement = self.shield_placement; + update = 1; + } + if ( update ) + { + if ( self.prev_shield_placement == 0 ) + { + self attachriotshield(); + return; + } + else if ( self.prev_shield_placement == 1 ) + { + self attachriotshield( level.carriedshieldmodel[ self.prev_shield_damage_level ], "tag_weapon_left" ); + self setriotshieldviewmodel( self.prev_shield_damage_level ); + return; + } + else if ( self.prev_shield_placement == 2 ) + { + self attachriotshield( level.stowedshieldmodel[ self.prev_shield_damage_level ], "tag_stowed_back" ); + return; + } + else + { + if ( self.prev_shield_placement == 3 ) + { + self attachriotshield(); + if ( isDefined( self.shield_ent ) ) + { + self.shield_ent setmodel( level.deployedshieldmodel[ self.prev_shield_damage_level ] ); + } + } + } + } +} + +updatestandaloneriotshieldmodel() +{ + update = 0; + if ( !isDefined( self.prev_shield_damage_level ) || self.prev_shield_damage_level != self.shield_damage_level ) + { + self.prev_shield_damage_level = self.shield_damage_level; + update = 1; + } + if ( update ) + { + self setmodel( level.deployedshieldmodel[ self.prev_shield_damage_level ] ); + } +} + +watchshieldlaststand() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "watchShieldLastStand" ); + self endon( "watchShieldLastStand" ); + while ( 1 ) + { + self waittill( "weapons_taken_for_last_stand" ); + self.riotshield_hidden = 0; + if ( isDefined( self.hasriotshield ) && self.hasriotshield ) + { + if ( self.prev_shield_placement == 1 || self.prev_shield_placement == 2 ) + { + self.riotshield_hidden = 2; + self.shield_placement = 0; + self updateriotshieldmodel(); + } + } + str_notify = self waittill_any_return( "player_revived", "bled_out" ); + if ( str_notify == "player_revived" ) + { + if ( isDefined( self.riotshield_hidden ) && self.riotshield_hidden > 0 ) + { + self.shield_placement = self.riotshield_hidden; + self updateriotshieldmodel(); + } + } + else + { + self maps/mp/zombies/_zm_weap_riotshield_prison::player_take_riotshield(); + } + self.riotshield_hidden = undefined; + } +} + +trackriotshield() +{ + self endon( "death" ); + self endon( "disconnect" ); + self.hasriotshield = self hasweapon( level.riotshield_name ); + self.hasriotshieldequipped = self getcurrentweapon() == level.riotshield_name; + self.shield_placement = 0; + if ( self.hasriotshield ) + { + if ( self.hasriotshieldequipped ) + { + self.shield_placement = 1; + self updateriotshieldmodel(); + } + else + { + self.shield_placement = 2; + self updateriotshieldmodel(); + } + } + for ( ;; ) + { + self waittill( "weapon_change", newweapon ); + if ( newweapon == level.riotshield_name ) + { + if ( self.hasriotshieldequipped ) + { + continue; + } + else if ( isDefined( self.riotshieldentity ) ) + { + self notify( "destroy_riotshield" ); + } + self.shield_placement = 1; + self updateriotshieldmodel(); + if ( self.hasriotshield ) + { + break; + } + self.hasriotshield = 1; + self.hasriotshieldequipped = 1; + continue; + } + else if ( self ismantling() && newweapon == "none" ) + { + continue; + } + else + { + if ( self.hasriotshieldequipped ) + { +/# + assert( self.hasriotshield ); +#/ + self.hasriotshield = self hasweapon( level.riotshield_name ); + if ( isDefined( self.riotshield_hidden ) && self.riotshield_hidden ) + { + } + else + { + if ( self.hasriotshield ) + { + self.shield_placement = 2; + break; + } + else if ( isDefined( self.shield_ent ) ) + { +/# + assert( self.shield_placement == 3 ); +#/ + break; + } + else + { + self.shield_placement = 0; + } + } + self updateriotshieldmodel(); + self.hasriotshieldequipped = 0; + break; + } + else if ( self.hasriotshield ) + { + if ( !self hasweapon( level.riotshield_name ) ) + { + self.shield_placement = 0; + self updateriotshieldmodel(); + self.hasriotshield = 0; + } + break; + } + else + { + if ( self hasweapon( level.riotshield_name ) ) + { + self.shield_placement = 2; + self updateriotshieldmodel(); + self.hasriotshield = 1; + } + } + } + } +} + +trackequipmentchange() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "equipment_dropped", equipname ); + self notify( "weapon_change" ); + } +} + +updateriotshieldplacement() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "deploy_riotshield" ); + self endon( "start_riotshield_deploy" ); + self endon( "weapon_change" ); + while ( 1 ) + { + placement = self canplaceriotshield( "raise_riotshield" ); + if ( placement[ "result" ] && riotshielddistancetest( placement[ "origin" ] ) ) + { + self restoreriotshieldviewmodel(); + self setplacementhint( 1 ); + } + else + { + self specialriotshieldviewmodel(); + self setplacementhint( 0 ); + } + wait 0,05; + } +} + +startriotshielddeploy() +{ + self notify( "start_riotshield_deploy" ); + self thread updateriotshieldplacement(); + self thread watchriotshielddeploy(); +} + +spawnriotshieldcover( origin, angles ) +{ + shield_ent = spawn( "script_model", origin, 1 ); + shield_ent.angles = angles; + shield_ent setowner( self ); + shield_ent.owner = self; + shield_ent.owner.shield_ent = shield_ent; + shield_ent.isriotshield = 1; + self.shield_placement = 3; + self updateriotshieldmodel(); + shield_ent setscriptmoverflag( 0 ); + self thread maps/mp/zombies/_zm_buildables::delete_on_disconnect( shield_ent, "destroy_riotshield", 1 ); + maps/mp/zombies/_zm_equipment::destructible_equipment_list_add( shield_ent ); + return shield_ent; +} + +watchriotshielddeploy() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "start_riotshield_deploy" ); + self waittill( "deploy_riotshield", deploy_attempt ); + self restoreriotshieldviewmodel(); + self setplacementhint( 1 ); + placement_hint = 0; + if ( deploy_attempt ) + { + placement = self canplaceriotshield( "deploy_riotshield" ); + if ( placement[ "result" ] && riotshielddistancetest( placement[ "origin" ] ) && self check_plant_position( placement[ "origin" ], placement[ "angles" ] ) ) + { + self doriotshielddeploy( placement[ "origin" ], placement[ "angles" ] ); + } + else + { + placement_hint = 1; + clip_max_ammo = weaponclipsize( level.riotshield_name ); + self setweaponammoclip( level.riotshield_name, clip_max_ammo ); + } + } + else + { + placement_hint = 1; + } + if ( placement_hint ) + { + self setriotshieldfailhint(); + } +} + +check_plant_position( origin, angles ) +{ + if ( isDefined( level.equipment_safe_to_drop ) ) + { + ret = 1; + test_ent = spawn( "script_model", origin ); + test_ent setmodel( level.deployedshieldmodel[ 0 ] ); + test_ent.angles = angles; + if ( !( self [[ level.equipment_safe_to_drop ]]( test_ent ) ) ) + { + ret = 0; + } + test_ent delete(); + return ret; + } + return 1; +} + +doriotshielddeploy( origin, angles ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "start_riotshield_deploy" ); + self notify( "deployed_riotshield" ); + self maps/mp/zombies/_zm_buildables::track_placed_buildables( level.riotshield_name ); + if ( isDefined( self.current_equipment ) && self.current_equipment == level.riotshield_name ) + { + self maps/mp/zombies/_zm_equipment::equipment_to_deployed( level.riotshield_name ); + } + zoffset = level.riotshield_placement_zoffset; + shield_ent = self spawnriotshieldcover( origin + ( 0, 0, zoffset ), angles ); + item_ent = deployriotshield( self, shield_ent ); + primaries = self getweaponslistprimaries(); +/# + assert( isDefined( item_ent ) ); + assert( !isDefined( self.riotshieldretrievetrigger ) ); + assert( !isDefined( self.riotshieldentity ) ); +#/ + self maps/mp/zombies/_zm_weapons::switch_back_primary_weapon( primaries[ 0 ] ); + if ( isDefined( level.equipment_planted ) ) + { + self [[ level.equipment_planted ]]( shield_ent, level.riotshield_name, self ); + } + if ( isDefined( level.equipment_safe_to_drop ) ) + { + if ( !( self [[ level.equipment_safe_to_drop ]]( shield_ent ) ) ) + { + self notify( "destroy_riotshield" ); + shield_ent delete(); + item_ent delete(); + return; + } + } + self.riotshieldretrievetrigger = item_ent; + self.riotshieldentity = shield_ent; + self thread watchdeployedriotshieldents(); + self thread deleteshieldondamage( self.riotshieldentity ); + self thread deleteshieldmodelonweaponpickup( self.riotshieldretrievetrigger ); + self thread deleteriotshieldonplayerdeath(); + self thread watchshieldtriggervisibility( self.riotshieldretrievetrigger ); + self.riotshieldentity thread watchdeployedriotshielddamage(); + return shield_ent; +} + +riotshielddistancetest( origin ) +{ +/# + assert( isDefined( origin ) ); +#/ + min_dist_squared = getDvarFloat( "riotshield_deploy_limit_radius" ); + min_dist_squared *= min_dist_squared; + i = 0; + while ( i < level.players.size ) + { + if ( isDefined( level.players[ i ].riotshieldentity ) ) + { + dist_squared = distancesquared( level.players[ i ].riotshieldentity.origin, origin ); + if ( min_dist_squared > dist_squared ) + { +/# + println( "Shield placement denied! Failed distance check to other riotshields." ); +#/ + return 0; + } + } + i++; + } + return 1; +} + +watchdeployedriotshieldents() +{ +/# + assert( isDefined( self.riotshieldretrievetrigger ) ); + assert( isDefined( self.riotshieldentity ) ); +#/ + riotshieldretrievetrigger = self.riotshieldretrievetrigger; + riotshieldentity = self.riotshieldentity; + self waittill_any( "destroy_riotshield", "disconnect", "alcatraz_shield_zm_taken" ); + if ( isDefined( self ) ) + { + self.shield_placement = 0; + self updateriotshieldmodel(); + } + if ( isDefined( riotshieldretrievetrigger ) ) + { + riotshieldretrievetrigger delete(); + } + if ( isDefined( riotshieldentity ) ) + { + riotshieldentity delete(); + } +} + +watchdeployedriotshielddamage() +{ + self endon( "death" ); + damagemax = getDvarInt( "riotshield_deployed_health" ); + self.damagetaken = 0; + while ( 1 ) + { + self.maxhealth = 100000; + self.health = self.maxhealth; + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + if ( isDefined( level.players_can_damage_riotshields ) && !level.players_can_damage_riotshields ) + { + continue; + } + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } +/# + if ( isDefined( self.owner ) ) + { + assert( isDefined( self.owner.team ) ); + } +#/ + while ( is_encounter() && attacker.team == self.owner.team && attacker != self.owner ) + { + continue; + } + if ( isDefined( level.riotshield_damage_callback ) ) + { + self.owner [[ level.riotshield_damage_callback ]]( damage, 0 ); + continue; + } + else + { + if ( type == "MOD_MELEE" ) + { + damage *= getDvarFloat( "riotshield_melee_damage_scale" ); + } + else if ( type == "MOD_PISTOL_BULLET" || type == "MOD_RIFLE_BULLET" ) + { + damage *= getDvarFloat( "riotshield_bullet_damage_scale" ); + } + else + { + if ( type != "MOD_GRENADE" && type != "MOD_GRENADE_SPLASH" && type != "MOD_EXPLOSIVE" && type != "MOD_EXPLOSIVE_SPLASH" || type == "MOD_PROJECTILE" && type == "MOD_PROJECTILE_SPLASH" ) + { + damage *= getDvarFloat( "riotshield_explosive_damage_scale" ); + break; + } + else + { + if ( type == "MOD_IMPACT" ) + { + damage *= getDvarFloat( "riotshield_projectile_damage_scale" ); + } + } + } + self.damagetaken += damage; + if ( self.damagetaken >= damagemax ) + { + self damagethendestroyriotshield(); + } + } + } +} + +damagethendestroyriotshield() +{ + self endon( "death" ); + self.owner.riotshieldretrievetrigger delete(); + self notsolid(); + self setclientflag( 14 ); + wait getDvarFloat( "riotshield_destroyed_cleanup_time" ); + self.owner notify( "destroy_riotshield" ); +} + +deleteshieldondamage( shield_ent ) +{ + shield_ent waittill( "death" ); + self notify( "destroy_riotshield" ); +} + +deleteshieldmodelonweaponpickup( shield_trigger ) +{ + shield_trigger waittill( "trigger", player ); + self maps/mp/zombies/_zm_equipment::equipment_from_deployed( level.riotshield_name ); + self notify( "destroy_riotshield" ); + if ( self != player ) + { + if ( isDefined( level.transferriotshield ) ) + { + [[ level.transferriotshield ]]( self, player ); + } + } +} + +watchshieldtriggervisibility( trigger ) +{ + self endon( "death" ); + trigger endon( "death" ); + while ( isDefined( trigger ) ) + { + players = get_players(); + _a759 = players; + _k759 = getFirstArrayKey( _a759 ); + while ( isDefined( _k759 ) ) + { + player = _a759[ _k759 ]; + pickup = 1; + if ( !isDefined( player ) ) + { + } + else if ( is_true( player.afterlife ) ) + { + trigger setinvisibletoplayer( player ); + wait 0,05; + } + else + { + if ( isDefined( level.cantransferriotshield ) ) + { + pickup = [[ level.cantransferriotshield ]]( self, player ); + } + if ( !isDefined( trigger ) ) + { + return; + } + if ( pickup ) + { + trigger setvisibletoplayer( player ); + } + else + { + trigger setinvisibletoplayer( player ); + } + wait 0,05; + } + _k759 = getNextArrayKey( _a759, _k759 ); + } + wait 0,05; + } +} + +deleteriotshieldonplayerdeath() +{ + self.riotshieldentity endon( "death" ); + self waittill( "death" ); + self notify( "destroy_riotshield" ); +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_weap_ballistic_knife.gsc b/zm_prison_patch/maps/mp/zombies/_zm_weap_ballistic_knife.gsc new file mode 100644 index 0000000..cd33180 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_weap_ballistic_knife.gsc @@ -0,0 +1,278 @@ +#include maps/mp/zombies/_zm_stats; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + if ( isDefined( level._uses_retrievable_ballisitic_knives ) && level._uses_retrievable_ballisitic_knives == 1 ) + { + precachemodel( "t5_weapon_ballistic_knife_projectile" ); + precachemodel( "t5_weapon_ballistic_knife_blade_retrieve" ); + } +} + +on_spawn( watcher, player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + player endon( "zmb_lost_knife" ); + level endon( "game_ended" ); + self waittill( "stationary", endpos, normal, angles, attacker, prey, bone ); + isfriendly = 0; + if ( isDefined( endpos ) ) + { + retrievable_model = spawn( "script_model", endpos ); + retrievable_model setmodel( "t5_weapon_ballistic_knife_blade_retrieve" ); + retrievable_model setowner( player ); + retrievable_model.owner = player; + retrievable_model.angles = angles; + retrievable_model.name = watcher.weapon; + if ( isDefined( prey ) ) + { + if ( isplayer( prey ) && player.team == prey.team ) + { + isfriendly = 1; + } + else + { + if ( isai( prey ) && player.team == prey.team ) + { + isfriendly = 1; + } + } + if ( !isfriendly ) + { + retrievable_model linkto( prey, bone ); + retrievable_model thread force_drop_knives_to_ground_on_death( player, prey ); + } + else + { + if ( isfriendly ) + { + retrievable_model physicslaunch( normal, ( randomint( 10 ), randomint( 10 ), randomint( 10 ) ) ); + normal = ( 0, 0, 1 ); + } + } + } + watcher.objectarray[ watcher.objectarray.size ] = retrievable_model; + if ( isfriendly ) + { + retrievable_model waittill( "stationary" ); + } + retrievable_model thread drop_knives_to_ground( player ); + if ( isfriendly ) + { + player notify( "ballistic_knife_stationary" ); + } + else + { + player notify( "ballistic_knife_stationary" ); + } + retrievable_model thread wait_to_show_glowing_model( prey ); + } +} + +wait_to_show_glowing_model( prey ) +{ + level endon( "game_ended" ); + self endon( "death" ); + wait 2; + self setmodel( "t5_weapon_ballistic_knife_blade_retrieve" ); +} + +on_spawn_retrieve_trigger( watcher, player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + player endon( "zmb_lost_knife" ); + level endon( "game_ended" ); + player waittill( "ballistic_knife_stationary", retrievable_model, normal, prey ); + if ( !isDefined( retrievable_model ) ) + { + return; + } + trigger_pos = []; + if ( isDefined( prey ) || isplayer( prey ) && isai( prey ) ) + { + trigger_pos[ 0 ] = prey.origin[ 0 ]; + trigger_pos[ 1 ] = prey.origin[ 1 ]; + trigger_pos[ 2 ] = prey.origin[ 2 ] + 10; + } + else + { + trigger_pos[ 0 ] = retrievable_model.origin[ 0 ] + ( 10 * normal[ 0 ] ); + trigger_pos[ 1 ] = retrievable_model.origin[ 1 ] + ( 10 * normal[ 1 ] ); + trigger_pos[ 2 ] = retrievable_model.origin[ 2 ] + ( 10 * normal[ 2 ] ); + } + pickup_trigger = spawn( "trigger_radius_use", ( trigger_pos[ 0 ], trigger_pos[ 1 ], trigger_pos[ 2 ] ) ); + pickup_trigger setcursorhint( "HINT_NOICON" ); + pickup_trigger.owner = player; + retrievable_model.retrievabletrigger = pickup_trigger; + hint_string = &"WEAPON_BALLISTIC_KNIFE_PICKUP"; + if ( isDefined( hint_string ) ) + { + pickup_trigger sethintstring( hint_string ); + } + else + { + pickup_trigger sethintstring( &"GENERIC_PICKUP" ); + } + pickup_trigger setteamfortrigger( player.team ); + player clientclaimtrigger( pickup_trigger ); + pickup_trigger enablelinkto(); + if ( isDefined( prey ) ) + { + pickup_trigger linkto( prey ); + } + else + { + pickup_trigger linkto( retrievable_model ); + } + if ( isDefined( level.knife_planted ) ) + { + [[ level.knife_planted ]]( retrievable_model, pickup_trigger, prey ); + } + retrievable_model thread watch_use_trigger( pickup_trigger, retrievable_model, ::pick_up, watcher.weapon, watcher.pickupsoundplayer, watcher.pickupsound ); + player thread watch_shutdown( pickup_trigger, retrievable_model ); +} + +debug_print( endpos ) +{ +/# + self endon( "death" ); + while ( 1 ) + { + print3d( endpos, "pickup_trigger" ); + wait 0,05; +#/ + } +} + +watch_use_trigger( trigger, model, callback, weapon, playersoundonuse, npcsoundonuse ) +{ + self endon( "death" ); + self endon( "delete" ); + level endon( "game_ended" ); + while ( 1 ) + { + trigger waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + if ( isDefined( trigger.triggerteam ) && player.team != trigger.triggerteam ) + { + continue; + } + if ( isDefined( trigger.claimedby ) && player != trigger.claimedby ) + { + continue; + } + if ( player usebuttonpressed() && !player.throwinggrenade && !player meleebuttonpressed() ) + { + if ( isDefined( playersoundonuse ) ) + { + player playlocalsound( playersoundonuse ); + } + if ( isDefined( npcsoundonuse ) ) + { + player playsound( npcsoundonuse ); + } + player thread [[ callback ]]( weapon, model, trigger ); + return; + } + else + { + } + } +} + +pick_up( weapon, model, trigger ) +{ + current_weapon = self getcurrentweapon(); + if ( current_weapon != weapon ) + { + clip_ammo = self getweaponammoclip( weapon ); + if ( !clip_ammo ) + { + self setweaponammoclip( weapon, 1 ); + } + else + { + new_ammo_stock = self getweaponammostock( weapon ) + 1; + self setweaponammostock( weapon, new_ammo_stock ); + } + } + else + { + new_ammo_stock = self getweaponammostock( weapon ) + 1; + self setweaponammostock( weapon, new_ammo_stock ); + } + self maps/mp/zombies/_zm_stats::increment_client_stat( "ballistic_knives_pickedup" ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "ballistic_knives_pickedup" ); + model destroy_ent(); + trigger destroy_ent(); +} + +destroy_ent() +{ + if ( isDefined( self ) ) + { + if ( isDefined( self.glowing_model ) ) + { + self.glowing_model delete(); + } + self delete(); + } +} + +watch_shutdown( trigger, model ) +{ + self waittill_any( "death", "disconnect", "zmb_lost_knife" ); + trigger destroy_ent(); + model destroy_ent(); +} + +drop_knives_to_ground( player ) +{ + player endon( "death" ); + player endon( "zmb_lost_knife" ); + for ( ;; ) + { + level waittill( "drop_objects_to_ground", origin, radius ); + if ( distancesquared( origin, self.origin ) < ( radius * radius ) ) + { + self physicslaunch( ( 0, 0, 1 ), vectorScale( ( 0, 0, 1 ), 5 ) ); + self thread update_retrieve_trigger( player ); + } + } +} + +force_drop_knives_to_ground_on_death( player, prey ) +{ + self endon( "death" ); + player endon( "zmb_lost_knife" ); + prey waittill( "death" ); + self unlink(); + self physicslaunch( ( 0, 0, 1 ), vectorScale( ( 0, 0, 1 ), 5 ) ); + self thread update_retrieve_trigger( player ); +} + +update_retrieve_trigger( player ) +{ + self endon( "death" ); + player endon( "zmb_lost_knife" ); + if ( isDefined( level.custom_update_retrieve_trigger ) ) + { + self [[ level.custom_update_retrieve_trigger ]]( player ); + return; + } + self waittill( "stationary" ); + trigger = self.retrievabletrigger; + trigger.origin = ( self.origin[ 0 ], self.origin[ 1 ], self.origin[ 2 ] + 10 ); + trigger linkto( self ); +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_weap_claymore.gsc b/zm_prison_patch/maps/mp/zombies/_zm_weap_claymore.gsc new file mode 100644 index 0000000..564c67f --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_weap_claymore.gsc @@ -0,0 +1,492 @@ +#include maps/mp/gametypes_zm/_weaponobjects; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + if ( !isDefined( level.claymores_max_per_player ) ) + { + level.claymores_max_per_player = 12; + } + trigs = getentarray( "claymore_purchase", "targetname" ); + i = 0; + while ( i < trigs.size ) + { + model = getent( trigs[ i ].target, "targetname" ); + if ( isDefined( model ) ) + { + model hide(); + } + i++; + } + array_thread( trigs, ::buy_claymores ); + level thread give_claymores_after_rounds(); + level.claymores_on_damage = ::satchel_damage; + level.pickup_claymores = ::pickup_claymores; + level.pickup_claymores_trigger_listener = ::pickup_claymores_trigger_listener; + level.claymore_detectiondot = cos( 70 ); + level.claymore_detectionmindist = 20; + level._effect[ "claymore_laser" ] = loadfx( "weapon/claymore/fx_claymore_laser" ); +} + +buy_claymores() +{ + self.zombie_cost = 1000; + self sethintstring( &"ZOMBIE_CLAYMORE_PURCHASE" ); + self setcursorhint( "HINT_NOICON" ); + self endon( "kill_trigger" ); + if ( !isDefined( self.stub ) ) + { + return; + } + if ( isDefined( self.stub ) && !isDefined( self.stub.claymores_triggered ) ) + { + self.stub.claymores_triggered = 0; + } + self.claymores_triggered = self.stub.claymores_triggered; + while ( 1 ) + { + self waittill( "trigger", who ); + while ( who in_revive_trigger() ) + { + continue; + } + while ( who has_powerup_weapon() ) + { + wait 0,1; + } + if ( is_player_valid( who ) ) + { + if ( who.score >= self.zombie_cost ) + { + if ( !who is_player_placeable_mine( "claymore_zm" ) ) + { + play_sound_at_pos( "purchase", self.origin ); + who maps/mp/zombies/_zm_score::minus_to_player_score( self.zombie_cost ); + who thread claymore_setup(); + who thread show_claymore_hint( "claymore_purchased" ); + who thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", "grenade" ); + if ( isDefined( self.stub ) ) + { + self.claymores_triggered = self.stub.claymores_triggered; + } + if ( self.claymores_triggered == 0 ) + { + model = getent( self.target, "targetname" ); + if ( isDefined( model ) ) + { + model thread maps/mp/zombies/_zm_weapons::weapon_show( who ); + } + else + { + if ( isDefined( self.clientfieldname ) ) + { + level setclientfield( self.clientfieldname, 1 ); + } + } + self.claymores_triggered = 1; + if ( isDefined( self.stub ) ) + { + self.stub.claymores_triggered = 1; + } + } + trigs = getentarray( "claymore_purchase", "targetname" ); + i = 0; + while ( i < trigs.size ) + { + trigs[ i ] setinvisibletoplayer( who ); + i++; + } + } + else who thread show_claymore_hint( "already_purchased" ); + } + } + } +} + +claymore_unitrigger_update_prompt( player ) +{ + if ( player is_player_placeable_mine( "claymore_zm" ) ) + { + return 0; + } + return 1; +} + +set_claymore_visible() +{ + players = get_players(); + trigs = getentarray( "claymore_purchase", "targetname" ); + while ( 1 ) + { + j = 0; + while ( j < players.size ) + { + while ( !players[ j ] is_player_placeable_mine( "claymore_zm" ) ) + { + i = 0; + while ( i < trigs.size ) + { + trigs[ i ] setinvisibletoplayer( players[ j ], 0 ); + i++; + } + } + j++; + } + wait 1; + players = get_players(); + } +} + +claymore_safe_to_plant() +{ + if ( self.owner.claymores.size >= level.claymores_max_per_player ) + { + return 0; + } + if ( isDefined( level.claymore_safe_to_plant ) ) + { + return self [[ level.claymore_safe_to_plant ]](); + } + return 1; +} + +claymore_wait_and_detonate() +{ + wait 0,1; + self detonate( self.owner ); +} + +claymore_watch() +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( "grenade_fire", claymore, weapname ); + if ( weapname == "claymore_zm" ) + { + claymore.owner = self; + claymore.team = self.team; + self notify( "zmb_enable_claymore_prompt" ); + if ( claymore claymore_safe_to_plant() ) + { + if ( isDefined( level.claymore_planted ) ) + { + self thread [[ level.claymore_planted ]]( claymore ); + } + claymore thread satchel_damage(); + claymore thread claymore_detonation(); + claymore thread play_claymore_effects(); + self maps/mp/zombies/_zm_stats::increment_client_stat( "claymores_planted" ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "claymores_planted" ); + break; + } + else + { + claymore thread claymore_wait_and_detonate(); + } + } + } +} + +claymore_setup() +{ + if ( !isDefined( self.claymores ) ) + { + self.claymores = []; + } + self thread claymore_watch(); + self giveweapon( "claymore_zm" ); + self set_player_placeable_mine( "claymore_zm" ); + self setactionslot( 4, "weapon", "claymore_zm" ); + self setweaponammostock( "claymore_zm", 2 ); +} + +adjust_trigger_origin( origin ) +{ + origin += vectorScale( ( 0, 0, 1 ), 20 ); + return origin; +} + +on_spawn_retrieve_trigger( watcher, player ) +{ + self maps/mp/gametypes_zm/_weaponobjects::onspawnretrievableweaponobject( watcher, player ); + if ( isDefined( self.pickuptrigger ) ) + { + self.pickuptrigger sethintlowpriority( 0 ); + } +} + +pickup_claymores() +{ + player = self.owner; + if ( !player hasweapon( "claymore_zm" ) ) + { + player thread claymore_watch(); + player giveweapon( "claymore_zm" ); + player set_player_placeable_mine( "claymore_zm" ); + player setactionslot( 4, "weapon", "claymore_zm" ); + player setweaponammoclip( "claymore_zm", 0 ); + player notify( "zmb_enable_claymore_prompt" ); + } + else + { + clip_ammo = player getweaponammoclip( self.name ); + clip_max_ammo = weaponclipsize( self.name ); + if ( clip_ammo >= clip_max_ammo ) + { + self destroy_ent(); + player notify( "zmb_disable_claymore_prompt" ); + return; + } + } + self pick_up(); + clip_ammo = player getweaponammoclip( self.name ); + clip_max_ammo = weaponclipsize( self.name ); + if ( clip_ammo >= clip_max_ammo ) + { + player notify( "zmb_disable_claymore_prompt" ); + } + player maps/mp/zombies/_zm_stats::increment_client_stat( "claymores_pickedup" ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "claymores_pickedup" ); +} + +pickup_claymores_trigger_listener( trigger, player ) +{ + self thread pickup_claymores_trigger_listener_enable( trigger, player ); + self thread pickup_claymores_trigger_listener_disable( trigger, player ); +} + +pickup_claymores_trigger_listener_enable( trigger, player ) +{ + self endon( "delete" ); + while ( 1 ) + { + player waittill_any( "zmb_enable_claymore_prompt", "spawned_player" ); + if ( !isDefined( trigger ) ) + { + return; + } + trigger trigger_on(); + trigger linkto( self ); + } +} + +pickup_claymores_trigger_listener_disable( trigger, player ) +{ + self endon( "delete" ); + while ( 1 ) + { + player waittill( "zmb_disable_claymore_prompt" ); + if ( !isDefined( trigger ) ) + { + return; + } + trigger unlink(); + trigger trigger_off(); + } +} + +shouldaffectweaponobject( object ) +{ + pos = self.origin + vectorScale( ( 0, 0, 1 ), 32 ); + dirtopos = pos - object.origin; + objectforward = anglesToForward( object.angles ); + dist = vectordot( dirtopos, objectforward ); + if ( dist < level.claymore_detectionmindist ) + { + return 0; + } + dirtopos = vectornormalize( dirtopos ); + dot = vectordot( dirtopos, objectforward ); + return dot > level.claymore_detectiondot; +} + +claymore_detonation() +{ + self endon( "death" ); + self waittill_not_moving(); + detonateradius = 96; + damagearea = spawn( "trigger_radius", self.origin + ( 0, 0, 0 - detonateradius ), 4, detonateradius, detonateradius * 2 ); + damagearea setexcludeteamfortrigger( self.team ); + damagearea enablelinkto(); + damagearea linkto( self ); + if ( is_true( self.isonbus ) ) + { + damagearea setmovingplatformenabled( 1 ); + } + self.damagearea = damagearea; + self thread delete_claymores_on_death( self.owner, damagearea ); + self.owner.claymores[ self.owner.claymores.size ] = self; + while ( 1 ) + { + damagearea waittill( "trigger", ent ); + if ( isDefined( self.owner ) && ent == self.owner ) + { + continue; + } + while ( isDefined( ent.pers ) && isDefined( ent.pers[ "team" ] ) && ent.pers[ "team" ] == self.team ) + { + continue; + } + if ( isDefined( ent.ignore_claymore ) && ent.ignore_claymore ) + { + continue; + } + while ( !ent shouldaffectweaponobject( self ) ) + { + continue; + } + if ( ent damageconetrace( self.origin, self ) > 0 ) + { + self playsound( "wpn_claymore_alert" ); + wait 0,4; + if ( isDefined( self.owner ) ) + { + self detonate( self.owner ); + } + else + { + self detonate( undefined ); + } + return; + } + } +} + +delete_claymores_on_death( player, ent ) +{ + self waittill( "death" ); + if ( isDefined( player ) ) + { + arrayremovevalue( player.claymores, self ); + } + wait 0,05; + if ( isDefined( ent ) ) + { + ent delete(); + } +} + +satchel_damage() +{ + self setcandamage( 1 ); + self.health = 100000; + self.maxhealth = self.health; + attacker = undefined; + while ( 1 ) + { + self waittill( "damage", amount, attacker ); + if ( !isDefined( self ) ) + { + return; + } + self.health = self.maxhealth; + while ( !isplayer( attacker ) ) + { + continue; + } + if ( isDefined( self.owner ) && attacker == self.owner ) + { + continue; + } + while ( isDefined( attacker.pers ) && isDefined( attacker.pers[ "team" ] ) && attacker.pers[ "team" ] != level.zombie_team ) + { + continue; + } + } + if ( level.satchelexplodethisframe ) + { + wait ( 0,1 + randomfloat( 0,4 ) ); + } + else wait 0,05; + if ( !isDefined( self ) ) + { + return; + } + level.satchelexplodethisframe = 1; + thread reset_satchel_explode_this_frame(); + self detonate( attacker ); +} + +reset_satchel_explode_this_frame() +{ + wait 0,05; + level.satchelexplodethisframe = 0; +} + +play_claymore_effects() +{ + self endon( "death" ); + self waittill_not_moving(); + playfxontag( level._effect[ "claymore_laser" ], self, "tag_fx" ); +} + +give_claymores_after_rounds() +{ + while ( 1 ) + { + level waittill( "between_round_over" ); + while ( !level flag_exists( "teleporter_used" ) || !flag( "teleporter_used" ) ) + { + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ] is_player_placeable_mine( "claymore_zm" ) ) + { + players[ i ] giveweapon( "claymore_zm" ); + players[ i ] set_player_placeable_mine( "claymore_zm" ); + players[ i ] setactionslot( 4, "weapon", "claymore_zm" ); + players[ i ] setweaponammoclip( "claymore_zm", 2 ); + } + i++; + } + } + } +} + +init_hint_hudelem( x, y, alignx, aligny, fontscale, alpha ) +{ + self.x = x; + self.y = y; + self.alignx = alignx; + self.aligny = aligny; + self.fontscale = fontscale; + self.alpha = alpha; + self.sort = 20; +} + +setup_client_hintelem() +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( !isDefined( self.hintelem ) ) + { + self.hintelem = newclienthudelem( self ); + } + self.hintelem init_hint_hudelem( 320, 220, "center", "bottom", 1,6, 1 ); +} + +show_claymore_hint( string ) +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( string == "claymore_purchased" ) + { + text = &"ZOMBIE_CLAYMORE_HOWTO"; + } + else + { + text = &"ZOMBIE_CLAYMORE_ALREADY_PURCHASED"; + } + self setup_client_hintelem(); + self.hintelem settext( text ); + wait 3,5; + self.hintelem settext( "" ); +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_weap_riotshield_prison.gsc b/zm_prison_patch/maps/mp/zombies/_zm_weap_riotshield_prison.gsc new file mode 100644 index 0000000..59454f8 --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_weap_riotshield_prison.gsc @@ -0,0 +1,778 @@ +#include maps/mp/zombies/_zm_audio; +#include maps/mp/animscripts/zm_death; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/gametypes_zm/_weaponobjects; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + maps/mp/zombies/_zm_riotshield_prison::init(); + set_zombie_var( "riotshield_cylinder_radius", 360 ); + set_zombie_var( "riotshield_fling_range", 90 ); + set_zombie_var( "riotshield_gib_range", 90 ); + set_zombie_var( "riotshield_gib_damage", 75 ); + set_zombie_var( "riotshield_knockdown_range", 90 ); + set_zombie_var( "riotshield_knockdown_damage", 15 ); + set_zombie_var( "riotshield_hit_points", 1500 ); + set_zombie_var( "riotshield_fling_damage_shield", 100 ); + set_zombie_var( "riotshield_knockdown_damage_shield", 15 ); + level.riotshield_network_choke_count = 0; + level.riotshield_gib_refs = []; + level.riotshield_gib_refs[ level.riotshield_gib_refs.size ] = "guts"; + level.riotshield_gib_refs[ level.riotshield_gib_refs.size ] = "right_arm"; + level.riotshield_gib_refs[ level.riotshield_gib_refs.size ] = "left_arm"; + level.riotshield_damage_callback = ::player_damage_shield; + level.deployed_riotshield_damage_callback = ::deployed_damage_shield; + level.transferriotshield = ::transferriotshield; + level.cantransferriotshield = ::cantransferriotshield; + maps/mp/zombies/_zm_spawner::register_zombie_damage_callback( ::riotshield_zombie_damage_response ); + maps/mp/zombies/_zm_equipment::register_equipment( "alcatraz_shield_zm", &"ZOMBIE_EQUIP_RIOTSHIELD_PICKUP_HINT_STRING", &"ZOMBIE_EQUIP_RIOTSHIELD_HOWTO", "riotshield_zm_icon", "riotshield", ::riotshield_activation_watcher_thread, undefined, ::dropshield, ::pickupshield ); + maps/mp/gametypes_zm/_weaponobjects::createretrievablehint( "riotshield", &"ZOMBIE_EQUIP_RIOTSHIELD_PICKUP_HINT_STRING" ); + onplayerconnect_callback( ::onplayerconnect ); +} + +onplayerconnect() +{ + self.player_shield_reset_health = ::player_init_shield_health; + self.player_shield_apply_damage = ::player_damage_shield; + self.player_shield_reset_location = ::player_init_shield_location; + self thread watchriotshielduse(); + self thread watchriotshieldmelee(); + self thread player_watch_laststand(); +} + +dropshield() +{ + self.shield_placement = 0; + self maps/mp/zombies/_zm_riotshield_prison::updateriotshieldmodel(); + item = self maps/mp/zombies/_zm_equipment::placed_equipment_think( "t6_wpn_zmb_shield_dlc2_dmg0_world", "alcatraz_shield_zm", self.origin + vectorScale( ( 0, 0, 1 ), 30 ), self.angles ); + if ( isDefined( item ) ) + { + item.shielddamagetaken = self.shielddamagetaken; + item.original_owner = self; + item.owner = undefined; + item.name = level.riotshield_name; + item.isriotshield = 1; + item deployed_damage_shield( 0 ); + item setscriptmoverflag( 0 ); + item.requires_pickup = 1; + item thread watchtoofriendly( self ); + } + self takeweapon( level.riotshield_name ); + return item; +} + +watchtoofriendly( player ) +{ + wait 1; + if ( isDefined( self ) && isDefined( player ) && distance2dsquared( self.origin, player.origin ) < 36 ) + { + if ( isalive( player ) ) + { + player playlocalsound( level.zmb_laugh_alias ); + } + player maps/mp/zombies/_zm_stats::increment_client_stat( "cheat_total", 0 ); + self deployed_damage_shield( 2000 ); + } +} + +pickupshield( item ) +{ + item.owner = self; + damage = item.shielddamagetaken; + damagemax = level.zombie_vars[ "riotshield_hit_points" ]; + self.shielddamagetaken = damage; + self player_set_shield_health( damage, damagemax ); +} + +placeshield( origin, angles ) +{ + if ( self getcurrentweapon() != level.riotshield_name ) + { + self switchtoweapon( level.riotshield_name ); + self waittill( "weapon_change" ); + } + item = self maps/mp/zombies/_zm_riotshield_prison::doriotshielddeploy( origin, angles ); + if ( isDefined( item ) ) + { + item.origin = self.origin + vectorScale( ( 0, 0, 1 ), 30 ); + item.angles = self.angles; + item.owner = self; + } + return item; +} + +cantransferriotshield( fromplayer, toplayer ) +{ + if ( isDefined( toplayer.screecher_weapon ) ) + { + return 0; + } + if ( isDefined( toplayer.is_drinking ) && toplayer.is_drinking > 0 ) + { + return 0; + } + if ( toplayer maps/mp/zombies/_zm_laststand::player_is_in_laststand() || toplayer in_revive_trigger() ) + { + return 0; + } + if ( toplayer isthrowinggrenade() ) + { + return 0; + } + if ( fromplayer == toplayer ) + { + return 1; + } + if ( toplayer is_player_equipment( level.riotshield_name ) && toplayer.shield_placement != 3 ) + { + return 0; + } + if ( fromplayer.session_team != toplayer.session_team ) + { + return 0; + } + return 1; +} + +transferriotshield( fromplayer, toplayer ) +{ + damage = fromplayer.shielddamagetaken; + toplayer player_take_riotshield(); + fromplayer player_take_riotshield(); + toplayer.shielddamagetaken = damage; + toplayer.shield_placement = 3; + toplayer.shield_damage_level = 0; + toplayer maps/mp/zombies/_zm_equipment::equipment_give( "alcatraz_shield_zm" ); + toplayer switchtoweapon( "alcatraz_shield_zm" ); + damagemax = level.zombie_vars[ "riotshield_hit_points" ]; + toplayer player_set_shield_health( damage, damagemax ); +} + +player_take_riotshield() +{ + self notify( "destroy_riotshield" ); + if ( self getcurrentweapon() == "alcatraz_shield_zm" ) + { + new_primary = ""; + if ( isDefined( self.laststand ) && self.laststand ) + { + new_primary = self.laststandpistol; + self giveweapon( new_primary ); + } + else + { + primaryweapons = self getweaponslistprimaries(); + i = 0; + while ( i < primaryweapons.size ) + { + if ( primaryweapons[ i ] != "alcatraz_shield_zm" ) + { + new_primary = primaryweapons[ i ]; + break; + } + else + { + i++; + } + } + if ( new_primary == "" ) + { + self maps/mp/zombies/_zm_weapons::give_fallback_weapon(); + new_primary = "zombie_fists_zm"; + } + } + self switchtoweaponimmediate( new_primary ); + self playsound( "wpn_riotshield_zm_destroy" ); + self waittill( "weapon_change" ); + } + self maps/mp/zombies/_zm_riotshield_prison::removeriotshield(); + self maps/mp/zombies/_zm_equipment::equipment_take( "alcatraz_shield_zm" ); + self.hasriotshield = 0; + self.hasriotshieldequipped = 0; +} + +player_watch_laststand() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "entering_last_stand" ); + if ( self getcurrentweapon() == "alcatraz_shield_zm" ) + { + new_primary = self.laststandpistol; + self giveweapon( new_primary ); + self switchtoweaponimmediate( new_primary ); + } + } +} + +player_init_shield_health() +{ + retval = self.shielddamagetaken > 0; + self.shielddamagetaken = 0; + self.shield_damage_level = 0; + self maps/mp/zombies/_zm_riotshield_prison::updateriotshieldmodel(); + return retval; +} + +player_init_shield_location() +{ + self.hasriotshield = 1; + self.hasriotshieldequipped = 0; + self.shield_placement = 2; + self maps/mp/zombies/_zm_riotshield_prison::updateriotshieldmodel(); +} + +player_set_shield_health( damage, max_damage ) +{ + shieldhealth = int( ( 100 * ( max_damage - damage ) ) / max_damage ); + if ( shieldhealth >= 50 ) + { + self.shield_damage_level = 0; + } + else if ( shieldhealth >= 25 ) + { + self.shield_damage_level = 2; + } + else + { + self.shield_damage_level = 3; + } + self maps/mp/zombies/_zm_riotshield_prison::updateriotshieldmodel(); +} + +deployed_set_shield_health( damage, max_damage ) +{ + shieldhealth = int( ( 100 * ( max_damage - damage ) ) / max_damage ); + if ( shieldhealth >= 50 ) + { + self.shield_damage_level = 0; + } + else if ( shieldhealth >= 25 ) + { + self.shield_damage_level = 2; + } + else + { + self.shield_damage_level = 3; + } + self maps/mp/zombies/_zm_riotshield_prison::updatestandaloneriotshieldmodel(); +} + +player_damage_shield( idamage, bheld ) +{ + damagemax = level.zombie_vars[ "riotshield_hit_points" ]; + if ( !isDefined( self.shielddamagetaken ) ) + { + self.shielddamagetaken = 0; + } + self.shielddamagetaken += idamage; + if ( self.shielddamagetaken >= damagemax ) + { + if ( bheld || !isDefined( self.shield_ent ) ) + { + self playrumbleonentity( "damage_heavy" ); + earthquake( 1, 0,75, self.origin, 100 ); + } + else + { + if ( isDefined( self.shield_ent ) ) + { + if ( is_true( self.shield_ent.destroy_begun ) ) + { + return; + } + self.shield_ent.destroy_begun = 1; + shield_origin = self.shield_ent.origin; + level thread maps/mp/zombies/_zm_equipment::equipment_disappear_fx( shield_origin, level._riotshield_dissapear_fx ); + wait 1; + playsoundatposition( "wpn_riotshield_zm_destroy", shield_origin ); + } + } + self thread player_take_riotshield(); + } + else + { + if ( bheld ) + { + self playrumbleonentity( "damage_light" ); + earthquake( 0,5, 0,5, self.origin, 100 ); + } + self player_set_shield_health( self.shielddamagetaken, damagemax ); + self playsound( "fly_riotshield_zm_impact_zombies" ); + } +} + +deployed_damage_shield( idamage ) +{ + damagemax = level.zombie_vars[ "riotshield_hit_points" ]; + if ( !isDefined( self.shielddamagetaken ) ) + { + self.shielddamagetaken = 0; + } + self.shielddamagetaken += idamage; + if ( self.shielddamagetaken >= damagemax ) + { + shield_origin = self.origin; + if ( isDefined( self.stub ) ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.stub ); + } + if ( isDefined( self.original_owner ) ) + { + self.original_owner maps/mp/zombies/_zm_equipment::equipment_take( "alcatraz_shield_zm" ); + } + maps/mp/zombies/_zm_equipment::equipment_disappear_fx( shield_origin, level._riotshield_dissapear_fx ); + playsoundatposition( "wpn_riotshield_zm_destroy", shield_origin ); + self_delete(); + } + else + { + self deployed_set_shield_health( self.shielddamagetaken, damagemax ); + } +} + +riotshield_activation_watcher_thread() +{ + self endon( "zombified" ); + self endon( "disconnect" ); + self endon( "alcatraz_shield_zm_taken" ); + while ( 1 ) + { + self waittill_either( "alcatraz_shield_zm_activate", "alcatraz_shield_zm_deactivate" ); + } +} + +watchriotshielduse() +{ + self endon( "death" ); + self endon( "disconnect" ); + self.shielddamagetaken = 0; + self thread maps/mp/zombies/_zm_riotshield_prison::trackriotshield(); + self thread maps/mp/zombies/_zm_riotshield_prison::trackequipmentchange(); + self thread maps/mp/zombies/_zm_riotshield_prison::watchshieldlaststand(); + self thread trackstuckzombies(); + for ( ;; ) + { + self waittill( "raise_riotshield" ); + self thread maps/mp/zombies/_zm_riotshield_prison::startriotshielddeploy(); + } +} + +watchriotshieldmelee() +{ + for ( ;; ) + { + self waittill( "weapon_melee", weapon ); + if ( weapon == level.riotshield_name ) + { + self riotshield_melee(); + } + } +} + +is_riotshield_damage( mod, player, amount ) +{ + if ( mod == "MOD_MELEE" && player hasweapon( level.riotshield_name ) && amount < 10 ) + { + return 1; + } + return 0; +} + +riotshield_damage( amount ) +{ +} + +riotshield_fling_zombie( player, fling_vec, index ) +{ + if ( !isDefined( self ) || !isalive( self ) ) + { + return; + } + if ( isDefined( self.ignore_riotshield ) && self.ignore_riotshield ) + { + return; + } + if ( isDefined( self.riotshield_fling_func ) ) + { + self [[ self.riotshield_fling_func ]]( player ); + return; + } + damage = 2500; + self dodamage( damage, player.origin, player, player, "", "MOD_IMPACT" ); + if ( self.health < 1 ) + { + self.riotshield_death = 1; + self startragdoll(); + self launchragdoll( fling_vec ); + } +} + +zombie_knockdown( player, gib ) +{ + damage = level.zombie_vars[ "riotshield_knockdown_damage" ]; + if ( isDefined( level.override_riotshield_damage_func ) ) + { + self [[ level.override_riotshield_damage_func ]]( player, gib ); + } + else + { + if ( gib ) + { + self.a.gib_ref = random( level.riotshield_gib_refs ); + self thread maps/mp/animscripts/zm_death::do_gib(); + } + self dodamage( damage, player.origin, player ); + } +} + +riotshield_knockdown_zombie( player, gib ) +{ + self endon( "death" ); + playsoundatposition( "vox_riotshield_forcehit", self.origin ); + playsoundatposition( "wpn_riotshield_proj_impact", self.origin ); + if ( !isDefined( self ) || !isalive( self ) ) + { + return; + } + if ( isDefined( self.riotshield_knockdown_func ) ) + { + self [[ self.riotshield_knockdown_func ]]( player, gib ); + } + else + { + self zombie_knockdown( player, gib ); + } + self dodamage( level.zombie_vars[ "riotshield_knockdown_damage" ], player.origin, player ); + self playsound( "fly_riotshield_forcehit" ); +} + +riotshield_get_enemies_in_range() +{ + view_pos = self geteye(); + zombies = get_array_of_closest( view_pos, get_round_enemy_array(), undefined, undefined, 2 * level.zombie_vars[ "riotshield_knockdown_range" ] ); + if ( !isDefined( zombies ) ) + { + return; + } + knockdown_range_squared = level.zombie_vars[ "riotshield_knockdown_range" ] * level.zombie_vars[ "riotshield_knockdown_range" ]; + gib_range_squared = level.zombie_vars[ "riotshield_gib_range" ] * level.zombie_vars[ "riotshield_gib_range" ]; + fling_range_squared = level.zombie_vars[ "riotshield_fling_range" ] * level.zombie_vars[ "riotshield_fling_range" ]; + cylinder_radius_squared = level.zombie_vars[ "riotshield_cylinder_radius" ] * level.zombie_vars[ "riotshield_cylinder_radius" ]; + forward_view_angles = self getweaponforwarddir(); + end_pos = view_pos + vectorScale( forward_view_angles, level.zombie_vars[ "riotshield_knockdown_range" ] ); +/# + if ( getDvarInt( #"BF480CE9" ) == 2 ) + { + near_circle_pos = view_pos + vectorScale( forward_view_angles, 2 ); + circle( near_circle_pos, level.zombie_vars[ "riotshield_cylinder_radius" ], ( 0, 0, 1 ), 0, 0, 100 ); + line( near_circle_pos, end_pos, ( 0, 0, 1 ), 1, 0, 100 ); + circle( end_pos, level.zombie_vars[ "riotshield_cylinder_radius" ], ( 0, 0, 1 ), 0, 0, 100 ); +#/ + } + i = 0; + while ( i < zombies.size ) + { + if ( !isDefined( zombies[ i ] ) || !isalive( zombies[ i ] ) ) + { + i++; + continue; + } + else + { + test_origin = zombies[ i ] getcentroid(); + test_range_squared = distancesquared( view_pos, test_origin ); + if ( test_range_squared > knockdown_range_squared ) + { + zombies[ i ] riotshield_debug_print( "range", ( 0, 0, 1 ) ); + return; + } + normal = vectornormalize( test_origin - view_pos ); + dot = vectordot( forward_view_angles, normal ); + if ( dot <= 0 ) + { + zombies[ i ] riotshield_debug_print( "dot", ( 0, 0, 1 ) ); + i++; + continue; + } + else radial_origin = pointonsegmentnearesttopoint( view_pos, end_pos, test_origin ); + if ( distancesquared( test_origin, radial_origin ) > cylinder_radius_squared ) + { + zombies[ i ] riotshield_debug_print( "cylinder", ( 0, 0, 1 ) ); + i++; + continue; + } + else if ( zombies[ i ] damageconetrace( view_pos, self ) == 0 ) + { + zombies[ i ] riotshield_debug_print( "cone", ( 0, 0, 1 ) ); + i++; + continue; + } + else if ( test_range_squared < fling_range_squared ) + { + level.riotshield_fling_enemies[ level.riotshield_fling_enemies.size ] = zombies[ i ]; + dist_mult = ( fling_range_squared - test_range_squared ) / fling_range_squared; + fling_vec = vectornormalize( test_origin - view_pos ); + if ( test_range_squared >= 5000 ) + { + fling_vec += vectornormalize( test_origin - radial_origin ); + } + fling_vec = ( fling_vec[ 0 ], fling_vec[ 1 ], abs( fling_vec[ 2 ] ) ); + fling_vec = vectorScale( fling_vec, 100 + ( 100 * dist_mult ) ); + level.riotshield_fling_vecs[ level.riotshield_fling_vecs.size ] = fling_vec; + zombies[ i ] riotshield_debug_print( "fling", ( 0, 0, 1 ) ); + i++; + continue; + } + else + { + level.riotshield_knockdown_enemies[ level.riotshield_knockdown_enemies.size ] = zombies[ i ]; + level.riotshield_knockdown_gib[ level.riotshield_knockdown_gib.size ] = 0; + zombies[ i ] riotshield_debug_print( "knockdown", ( 0, 0, 1 ) ); + } + } + i++; + } +} + +riotshield_network_choke() +{ + level.riotshield_network_choke_count++; + if ( level.riotshield_network_choke_count % 10 ) + { + wait_network_frame(); + wait_network_frame(); + wait_network_frame(); + } +} + +riotshield_melee() +{ + if ( !isDefined( level.riotshield_knockdown_enemies ) ) + { + level.riotshield_knockdown_enemies = []; + level.riotshield_knockdown_gib = []; + level.riotshield_fling_enemies = []; + level.riotshield_fling_vecs = []; + } + self riotshield_get_enemies_in_range(); + shield_damage = 0; + level.riotshield_network_choke_count = 0; + i = 0; + while ( i < level.riotshield_fling_enemies.size ) + { + riotshield_network_choke(); + if ( isDefined( level.riotshield_fling_enemies[ i ] ) ) + { + level.riotshield_fling_enemies[ i ] thread riotshield_fling_zombie( self, level.riotshield_fling_vecs[ i ], i ); + shield_damage += level.zombie_vars[ "riotshield_fling_damage_shield" ]; + } + i++; + } + i = 0; + while ( i < level.riotshield_knockdown_enemies.size ) + { + riotshield_network_choke(); + level.riotshield_knockdown_enemies[ i ] thread riotshield_knockdown_zombie( self, level.riotshield_knockdown_gib[ i ] ); + shield_damage += level.zombie_vars[ "riotshield_knockdown_damage_shield" ]; + i++; + } + level.riotshield_knockdown_enemies = []; + level.riotshield_knockdown_gib = []; + level.riotshield_fling_enemies = []; + level.riotshield_fling_vecs = []; + if ( shield_damage ) + { + self player_damage_shield( shield_damage, 0 ); + } +} + +trackstuckzombies() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "deployed_riotshield" ); + if ( isDefined( self.riotshieldentity ) ) + { + self thread watchstuckzombies(); + } + } +} + +attack_shield( shield ) +{ + self endon( "death" ); + shield.owner endon( "death" ); + shield.owner endon( "disconnect" ); + shield.owner endon( "start_riotshield_deploy" ); + shield.owner endon( "destroy_riotshield" ); + if ( isDefined( self.doing_shield_attack ) && self.doing_shield_attack ) + { + return 0; + } + self.old_origin = self.origin; + if ( getDvar( "zombie_shield_attack_freq" ) == "" ) + { + setdvar( "zombie_shield_attack_freq", "15" ); + } + freq = getDvarInt( "zombie_shield_attack_freq" ); + self.doing_shield_attack = 1; + self.enemyoverride[ 0 ] = shield.origin; + self.enemyoverride[ 1 ] = shield; + wait ( randomint( 100 ) / 100 ); + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "attack", self.animname ); + attackanim = "zm_riotshield_melee"; + if ( !self.has_legs ) + { + attackanim += "_crawl"; + } + self orientmode( "face point", shield.origin ); + self animscripted( self.origin, flat_angle( vectorToAngle( shield.origin - self.origin ) ), attackanim ); + if ( isDefined( shield.owner.player_shield_apply_damage ) ) + { + shield.owner [[ shield.owner.player_shield_apply_damage ]]( 100, 0 ); + } + else + { + shield.owner player_damage_shield( 100, 0 ); + } + self thread attack_shield_stop( shield ); + wait ( randomint( 100 ) / 100 ); + self.doing_shield_attack = 0; + self orientmode( "face default" ); +} + +attack_shield_stop( shield ) +{ + self notify( "attack_shield_stop" ); + self endon( "attack_shield_stop" ); + self endon( "death" ); + shield waittill( "death" ); + self stopanimscripted(); + if ( isDefined( self.doing_shield_attack ) && self.doing_shield_attack ) + { + breachanim = "zm_riotshield_breakthrough"; + if ( !self.has_legs ) + { + breachanim += "_crawl"; + } + self animscripted( self.origin, flat_angle( self.angles ), breachanim ); + } +} + +window_notetracks( msg, player ) +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( msg, notetrack ); + if ( notetrack == "end" ) + { + return; + } + if ( notetrack == "fire" ) + { + player player_damage_shield( 100, 0 ); + } + } +} + +watchstuckzombies() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "start_riotshield_deploy" ); + self endon( "destroy_riotshield" ); + self endon( "deployed_riotshield" ); + level endon( "intermission" ); + self.riotshieldentity maps/mp/zombies/_zm_equipment::item_attract_zombies(); +} + +riotshield_active() +{ + return self maps/mp/zombies/_zm_equipment::is_equipment_active( "alcatraz_shield_zm" ); +} + +riotshield_debug_print( msg, color ) +{ +/# + if ( !getDvarInt( #"BF480CE9" ) ) + { + return; + } + if ( !isDefined( color ) ) + { + color = ( 0, 0, 1 ); + } + print3d( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), msg, color, 1, 1, 40 ); +#/ +} + +shield_zombie_attract_func( poi ) +{ +} + +shield_zombie_arrive_func( poi ) +{ + self endon( "death" ); + self endon( "zombie_acquire_enemy" ); + self endon( "path_timer_done" ); + self waittill( "goal" ); + if ( isDefined( poi.owner ) ) + { + poi.owner player_damage_shield( 100, 0 ); + if ( isDefined( poi.owner.player_shield_apply_damage ) ) + { + poi.owner [[ poi.owner.player_shield_apply_damage ]]( 100, 0 ); + } + } +} + +createriotshieldattractor() +{ + self create_zombie_point_of_interest( 50, 8, 0, 1, ::shield_zombie_attract_func, ::shield_zombie_arrive_func ); + self thread create_zombie_point_of_interest_attractor_positions( 4, 15, 15 ); + return get_zombie_point_of_interest( self.origin ); +} + +riotshield_zombie_damage_response( mod, hit_location, hit_origin, player, amount ) +{ + if ( self is_riotshield_damage( mod, player, amount ) ) + { + self riotshield_damage( amount ); + return 1; + } + return 0; +} + +watchriotshieldattractor() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "start_riotshield_deploy" ); + self endon( "destroy_riotshield" ); + self endon( "deployed_riotshield" ); + poi = self.riotshieldentity createriotshieldattractor(); +} + +trackriotshieldattractor() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "deployed_riotshield" ); + self thread watchriotshieldattractor(); + } +} diff --git a/zm_prison_patch/maps/mp/zombies/_zm_weap_tomahawk.gsc b/zm_prison_patch/maps/mp/zombies/_zm_weap_tomahawk.gsc new file mode 100644 index 0000000..02c98ed --- /dev/null +++ b/zm_prison_patch/maps/mp/zombies/_zm_weap_tomahawk.gsc @@ -0,0 +1,672 @@ +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + registerclientfield( "toplayer", "tomahawk_in_use", 9000, 2, "int" ); + registerclientfield( "toplayer", "upgraded_tomahawk_in_use", 9000, 1, "int" ); + registerclientfield( "scriptmover", "play_tomahawk_fx", 9000, 2, "int" ); + registerclientfield( "actor", "play_tomahawk_hit_sound", 9000, 1, "int" ); + onplayerconnect_callback( ::tomahawk_on_player_connect ); + maps/mp/zombies/_zm_weapons::include_zombie_weapon( "bouncing_tomahawk_zm", 0 ); + maps/mp/zombies/_zm_weapons::include_zombie_weapon( "upgraded_tomahawk_zm", 0 ); + maps/mp/zombies/_zm_weapons::include_zombie_weapon( "zombie_tomahawk_flourish", 0 ); + maps/mp/zombies/_zm_weapons::add_zombie_weapon( "bouncing_tomahawk_zm", "zombie_tomahawk_flourish", &"ZOMBIE_WEAPON_SATCHEL_2000", 2000, "wpck_monkey", "", undefined, 1 ); + maps/mp/zombies/_zm_weapons::add_zombie_weapon( "upgraded_tomahawk_zm", "zombie_tomahawk_flourish", &"ZOMBIE_WEAPON_SATCHEL_2000", 2000, "wpck_monkey", "", undefined, 1 ); + level thread tomahawk_pickup(); + level.zombie_weapons_no_max_ammo = []; + level.zombie_weapons_no_max_ammo[ "bouncing_tomahawk_zm" ] = 1; + level.zombie_weapons_no_max_ammo[ "upgraded_tomahawk_zm" ] = 1; + level.a_tomahawk_pickup_funcs = []; +} + +tomahawk_on_player_connect() +{ + self.current_tomahawk_weapon = "bouncing_tomahawk_zm"; + self.current_tactical_grenade = "bouncing_tomahawk_zm"; + self thread watch_for_tomahawk_throw(); + self thread watch_for_tomahawk_charge(); +} + +watch_for_tomahawk_throw() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "grenade_fire", grenade, weapname ); + while ( !issubstr( weapname, "tomahawk_zm" ) ) + { + continue; + } + grenade.use_grenade_special_bookmark = 1; + grenade.grenade_multiattack_bookmark_count = 1; + grenade.low_level_instant_kill_charge = 1; + grenade.owner = self; + self notify( "throwing_tomahawk" ); + if ( isDefined( self.n_tomahawk_cooking_time ) ) + { + grenade.n_cookedtime = grenade.birthtime - self.n_tomahawk_cooking_time; + } + else + { + grenade.n_cookedtime = 0; + } + self thread check_for_time_out( grenade ); + self thread tomahawk_thrown( grenade ); + } +} + +watch_for_tomahawk_charge() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "grenade_pullback", weaponname ); + while ( !issubstr( weaponname, "tomahawk_zm" ) ) + { + continue; + } + self thread watch_for_grenade_cancel(); + self thread play_charge_fx(); + self.n_tomahawk_cooking_time = getTime(); + self waittill_either( "grenade_fire", "grenade_throw_cancelled" ); + wait 0,1; + self.n_tomahawk_cooking_time = undefined; + } +} + +watch_for_grenade_cancel() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "grenade_fire" ); + waittillframeend; + weapon = "none"; + while ( self isthrowinggrenade() && weapon == "none" ) + { + self waittill( "weapon_change", weapon ); + } + self notify( "grenade_throw_cancelled" ); +} + +play_charge_fx() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "grenade_fire" ); + waittillframeend; + time_to_pulse = 1000; + while ( 1 ) + { + time = getTime() - self.n_tomahawk_cooking_time; + self.current_tactical_grenade = self get_player_tactical_grenade(); + if ( time >= time_to_pulse ) + { + if ( self.current_tactical_grenade == "upgraded_tomahawk_zm" ) + { + playfxontag( level._effect[ "tomahawk_charge_up_ug" ], self, "tag_origin" ); + } + else + { + playfxontag( level._effect[ "tomahawk_charge_up" ], self, "tag_origin" ); + } + time_to_pulse += 1000; + self playrumbleonentity( "reload_small" ); + } + if ( time_to_pulse > 2400 && self.current_tactical_grenade != "upgraded_tomahawk_zm" ) + { + return; + } + else + { + if ( time_to_pulse >= 3400 ) + { + return; + } + else + { + wait 0,05; + } + } + } +} + +get_grenade_charge_power( player ) +{ + player endon( "disconnect" ); + if ( self.n_cookedtime > 1000 && self.n_cookedtime < 2000 ) + { + if ( player.current_tomahawk_weapon == "upgraded_tomahawk_zm" ) + { + return 4,5; + } + return 1,5; + } + else + { + if ( self.n_cookedtime > 2000 && self.n_cookedtime < 3000 ) + { + if ( player.current_tomahawk_weapon == "upgraded_tomahawk_zm" ) + { + return 6; + } + return 2; + } + else + { + if ( self.n_cookedtime >= 3000 && player.current_tomahawk_weapon != "upgraded_tomahawk_zm" ) + { + return 2; + } + else + { + if ( self.n_cookedtime >= 3000 ) + { + return 3; + } + } + } + } + return 1; +} + +tomahawk_thrown( grenade ) +{ + self endon( "disconnect" ); + grenade endon( "in_hellhole" ); + grenade_owner = undefined; + if ( isDefined( grenade.owner ) ) + { + grenade_owner = grenade.owner; + } + playfxontag( level._effect[ "tomahawk_charged_trail" ], grenade, "tag_origin" ); + self setclientfieldtoplayer( "tomahawk_in_use", 2 ); + grenade waittill_either( "death", "time_out" ); + grenade_origin = grenade.origin; + a_zombies = getaispeciesarray( "axis", "all" ); + n_grenade_charge_power = grenade get_grenade_charge_power( self ); + a_zombies = get_array_of_closest( grenade_origin, a_zombies, undefined, undefined, 200 ); + a_powerups = get_array_of_closest( grenade_origin, level.active_powerups, undefined, undefined, 200 ); + while ( isDefined( level.a_tomahawk_pickup_funcs ) ) + { + _a243 = level.a_tomahawk_pickup_funcs; + _k243 = getFirstArrayKey( _a243 ); + while ( isDefined( _k243 ) ) + { + tomahawk_func = _a243[ _k243 ]; + if ( [[ tomahawk_func ]]( grenade, n_grenade_charge_power ) ) + { + return; + } + _k243 = getNextArrayKey( _a243, _k243 ); + } + } + if ( isDefined( a_powerups ) && a_powerups.size > 0 ) + { + m_tomahawk = tomahawk_spawn( grenade_origin, n_grenade_charge_power ); + m_tomahawk.n_grenade_charge_power = n_grenade_charge_power; + _a256 = a_powerups; + _k256 = getFirstArrayKey( _a256 ); + while ( isDefined( _k256 ) ) + { + powerup = _a256[ _k256 ]; + powerup.origin = grenade_origin; + powerup linkto( m_tomahawk ); + m_tomahawk.a_has_powerup = a_powerups; + _k256 = getNextArrayKey( _a256, _k256 ); + } + self thread tomahawk_return_player( m_tomahawk, 0 ); + return; + } + if ( !isDefined( a_zombies ) ) + { + m_tomahawk = tomahawk_spawn( grenade_origin, n_grenade_charge_power ); + m_tomahawk.n_grenade_charge_power = n_grenade_charge_power; + self thread tomahawk_return_player( m_tomahawk, 0 ); + return; + } + else + { + _a276 = a_zombies; + _k276 = getFirstArrayKey( _a276 ); + while ( isDefined( _k276 ) ) + { + ai_zombie = _a276[ _k276 ]; + ai_zombie.hit_by_tomahawk = 0; + _k276 = getNextArrayKey( _a276, _k276 ); + } + } + if ( isDefined( a_zombies[ 0 ] ) && isalive( a_zombies[ 0 ] ) ) + { + v_zombiepos = a_zombies[ 0 ].origin; + if ( distancesquared( grenade_origin, v_zombiepos ) <= 4900 ) + { + a_zombies[ 0 ] setclientfield( "play_tomahawk_hit_sound", 1 ); + n_tomahawk_damage = calculate_tomahawk_damage( a_zombies[ 0 ], n_grenade_charge_power, grenade ); + a_zombies[ 0 ] dodamage( n_tomahawk_damage, grenade_origin, self, grenade, "none", "MOD_GRENADE", 0, "bouncing_tomahawk_zm" ); + a_zombies[ 0 ].hit_by_tomahawk = 1; + self maps/mp/zombies/_zm_score::add_to_player_score( 10 ); + self thread tomahawk_ricochet_attack( grenade_origin, n_grenade_charge_power ); + } + else + { + m_tomahawk = tomahawk_spawn( grenade_origin, n_grenade_charge_power ); + m_tomahawk.n_grenade_charge_power = n_grenade_charge_power; + self thread tomahawk_return_player( m_tomahawk, 0 ); + } + } + else + { + m_tomahawk = tomahawk_spawn( grenade_origin, n_grenade_charge_power ); + m_tomahawk.n_grenade_charge_power = n_grenade_charge_power; + if ( isDefined( grenade ) ) + { + grenade delete(); + } + self thread tomahawk_return_player( m_tomahawk, 0 ); + } +} + +check_for_time_out( grenade ) +{ + self endon( "disconnect" ); + grenade endon( "death" ); + wait 0,5; + grenade notify( "time_out" ); +} + +tomahawk_ricochet_attack( grenade_origin, tomahawk_charge_power ) +{ + self endon( "disconnect" ); + a_zombies = getaispeciesarray( "axis", "all" ); + a_zombies = get_array_of_closest( grenade_origin, a_zombies, undefined, undefined, 300 ); + a_zombies = array_reverse( a_zombies ); + if ( !isDefined( a_zombies ) ) + { + m_tomahawk = tomahawk_spawn( grenade_origin, tomahawk_charge_power ); + m_tomahawk.n_grenade_charge_power = tomahawk_charge_power; + self thread tomahawk_return_player( m_tomahawk, 0 ); + return; + } + m_tomahawk = tomahawk_spawn( grenade_origin, tomahawk_charge_power ); + m_tomahawk.n_grenade_charge_power = tomahawk_charge_power; + self thread tomahawk_attack_zombies( m_tomahawk, a_zombies ); +} + +tomahawk_attack_zombies( m_tomahawk, a_zombies ) +{ + self endon( "disconnect" ); + if ( !isDefined( a_zombies ) ) + { + self thread tomahawk_return_player( m_tomahawk, 0 ); + return; + } + if ( a_zombies.size <= 4 ) + { + n_attack_limit = a_zombies.size; + } + else + { + n_attack_limit = 4; + } + i = 0; + while ( i < n_attack_limit ) + { + if ( isDefined( a_zombies[ i ] ) && isalive( a_zombies[ i ] ) ) + { + tag = "J_Head"; + if ( a_zombies[ i ].isdog ) + { + tag = "J_Spine1"; + } + if ( isDefined( a_zombies[ i ].hit_by_tomahawk ) && !a_zombies[ i ].hit_by_tomahawk ) + { + v_target = a_zombies[ i ] gettagorigin( tag ); + m_tomahawk moveto( v_target, 0,3 ); + m_tomahawk waittill( "movedone" ); + if ( isDefined( a_zombies[ i ] ) && isalive( a_zombies[ i ] ) ) + { + if ( self.current_tactical_grenade == "upgraded_tomahawk_zm" ) + { + playfxontag( level._effect[ "tomahawk_impact_ug" ], a_zombies[ i ], tag ); + } + else + { + playfxontag( level._effect[ "tomahawk_impact" ], a_zombies[ i ], tag ); + } + playfxontag( level._effect[ "tomahawk_fire_dot" ], a_zombies[ i ], "j_spineupper" ); + a_zombies[ i ] setclientfield( "play_tomahawk_hit_sound", 1 ); + n_tomahawk_damage = calculate_tomahawk_damage( a_zombies[ i ], m_tomahawk.n_grenade_charge_power, m_tomahawk ); + a_zombies[ i ] dodamage( n_tomahawk_damage, m_tomahawk.origin, self, m_tomahawk, "none", "MOD_GRENADE", 0, "bouncing_tomahawk_zm" ); + a_zombies[ i ].hit_by_tomahawk = 1; + self maps/mp/zombies/_zm_score::add_to_player_score( 10 ); + } + } + } + wait 0,2; + i++; + } + self thread tomahawk_return_player( m_tomahawk, n_attack_limit ); +} + +tomahawk_return_player( m_tomahawk, num_zombie_hit ) +{ + self endon( "disconnect" ); + n_dist = distance2dsquared( m_tomahawk.origin, self.origin ); + if ( !isDefined( num_zombie_hit ) ) + { + num_zombie_hit = 5; + } + while ( n_dist > 4096 ) + { + m_tomahawk moveto( self geteye(), 0,25 ); + if ( num_zombie_hit < 5 ) + { + self tomahawk_check_for_zombie( m_tomahawk ); + num_zombie_hit++; + } + wait 0,1; + n_dist = distance2dsquared( m_tomahawk.origin, self geteye() ); + } + while ( isDefined( m_tomahawk.a_has_powerup ) ) + { + _a470 = m_tomahawk.a_has_powerup; + _k470 = getFirstArrayKey( _a470 ); + while ( isDefined( _k470 ) ) + { + powerup = _a470[ _k470 ]; + if ( isDefined( powerup ) ) + { + powerup.origin = self.origin; + } + _k470 = getNextArrayKey( _a470, _k470 ); + } + } + m_tomahawk delete(); + self playsoundtoplayer( "wpn_tomahawk_catch_plr", self ); + self playsound( "wpn_tomahawk_catch_npc" ); + wait 5; + self playsoundtoplayer( "wpn_tomahawk_cooldown_done", self ); + self givemaxammo( self.current_tomahawk_weapon ); + a_zombies = getaispeciesarray( "axis", "all" ); + _a490 = a_zombies; + _k490 = getFirstArrayKey( _a490 ); + while ( isDefined( _k490 ) ) + { + ai_zombie = _a490[ _k490 ]; + ai_zombie.hit_by_tomahawk = 0; + _k490 = getNextArrayKey( _a490, _k490 ); + } + self setclientfieldtoplayer( "tomahawk_in_use", 3 ); +} + +tomahawk_check_for_zombie( grenade ) +{ + self endon( "disconnect" ); + grenade endon( "death" ); + a_zombies = getaispeciesarray( "axis", "all" ); + a_zombies = get_array_of_closest( grenade.origin, a_zombies, undefined, undefined, 100 ); + if ( isDefined( a_zombies[ 0 ] ) && distance2dsquared( grenade.origin, a_zombies[ 0 ].origin ) <= 10000 ) + { + if ( isDefined( a_zombies[ 0 ].hit_by_tomahawk ) && !a_zombies[ 0 ].hit_by_tomahawk ) + { + self tomahawk_hit_zombie( a_zombies[ 0 ], grenade ); + } + } +} + +tomahawk_hit_zombie( ai_zombie, grenade ) +{ + self endon( "disconnect" ); + if ( isDefined( ai_zombie ) && isalive( ai_zombie ) ) + { + tag = "J_Head"; + if ( ai_zombie.isdog ) + { + tag = "J_Spine1"; + } + v_target = ai_zombie gettagorigin( tag ); + grenade moveto( v_target, 0,3 ); + grenade waittill( "movedone" ); + if ( isDefined( ai_zombie ) && isalive( ai_zombie ) ) + { + if ( self.current_tactical_grenade == "upgraded_tomahawk_zm" ) + { + playfxontag( level._effect[ "tomahawk_impact_ug" ], ai_zombie, tag ); + } + else + { + playfxontag( level._effect[ "tomahawk_impact" ], ai_zombie, tag ); + } + ai_zombie setclientfield( "play_tomahawk_hit_sound", 1 ); + n_tomahawk_damage = calculate_tomahawk_damage( ai_zombie, grenade.n_grenade_charge_power, grenade ); + ai_zombie dodamage( n_tomahawk_damage, grenade.origin, self, grenade, "none", "MOD_GRENADE", 0, "bouncing_tomahawk_zm" ); + ai_zombie.hit_by_tomahawk = 1; + self maps/mp/zombies/_zm_score::add_to_player_score( 10 ); + } + } +} + +tomahawk_spawn( grenade_origin, charged ) +{ + m_tomahawk = spawn( "script_model", grenade_origin ); + m_tomahawk setmodel( "t6_wpn_zmb_tomahawk_world" ); + m_tomahawk thread tomahawk_spin(); + m_tomahawk playloopsound( "wpn_tomahawk_flying_loop" ); + if ( self.current_tactical_grenade == "upgraded_tomahawk_zm" ) + { + playfxontag( level._effect[ "tomahawk_trail_ug" ], m_tomahawk, "tag_origin" ); + } + else + { + playfxontag( level._effect[ "tomahawk_trail" ], m_tomahawk, "tag_origin" ); + } + if ( isDefined( charged ) && charged > 1 ) + { + playfxontag( level._effect[ "tomahawk_charged_trail" ], m_tomahawk, "tag_origin" ); + } + m_tomahawk.low_level_instant_kill_charge = 1; + return m_tomahawk; +} + +tomahawk_spin() +{ + self endon( "death" ); + while ( isDefined( self ) ) + { + self rotatepitch( 90, 0,2 ); + wait 0,15; + } +} + +tomahawk_pickup() +{ + flag_wait( "soul_catchers_charged" ); + flag_init( "tomahawk_pickup_complete" ); + door = getent( "tomahawk_room_door", "targetname" ); + door trigger_off(); + door connectpaths(); + s_pos_tomahawk = getstruct( "tomahawk_pickup_pos", "targetname" ); + m_tomahawk = spawn( "script_model", s_pos_tomahawk.origin ); + m_tomahawk.targetname = "spinning_tomahawk_pickup"; + m_tomahawk setmodel( "t6_wpn_zmb_tomahawk_world" ); + m_tomahawk setclientfield( "play_tomahawk_fx", 1 ); + m_tomahawk thread tomahawk_pickup_spin(); + m_tomahawk playloopsound( "amb_tomahawk_swirl" ); + s_pos_trigger = getstruct( "tomahawk_trigger_pos", "targetname" ); + trigger = spawn( "trigger_radius_use", s_pos_trigger.origin, 0, 100, 150 ); + trigger.script_noteworthy = "retriever_pickup_trigger"; + trigger usetriggerrequirelookat(); + trigger triggerignoreteam(); + trigger sethintstring( &"ZM_PRISON_TOMAHAWK_PICKUP" ); + trigger setcursorhint( "HINT_NOICON" ); + trigger_upgraded = spawn( "trigger_radius_use", s_pos_trigger.origin, 0, 100, 150 ); + trigger_upgraded usetriggerrequirelookat(); + trigger_upgraded triggerignoreteam(); + trigger_upgraded.script_noteworthy = "redeemer_pickup_trigger"; + trigger_upgraded sethintstring( &"ZM_PRISON_TOMAHAWK_UPGRADED_PICKUP" ); + trigger_upgraded setcursorhint( "HINT_NOICON" ); +/# + iprintlnbold( "GO FIND THE TOMAHAWK" ); +#/ + trigger thread tomahawk_pickup_trigger(); + trigger_upgraded thread tomahawk_pickup_trigger(); + flag_set( "tomahawk_pickup_complete" ); +} + +tomahawk_pickup_trigger() +{ + for ( ;; ) + { + while ( 1 ) + { + self waittill( "trigger", player ); + if ( isDefined( player.current_tactical_grenade ) && !issubstr( player.current_tactical_grenade, "tomahawk_zm" ) ) + { + player takeweapon( player.current_tactical_grenade ); + } + while ( player.current_tomahawk_weapon == "upgraded_tomahawk_zm" ) + { + if ( !is_true( player.afterlife ) ) + { + } + } + else player disable_player_move_states( 1 ); + gun = player getcurrentweapon(); + level notify( "bouncing_tomahawk_zm_aquired" ); + player maps/mp/zombies/_zm_stats::increment_client_stat( "prison_tomahawk_acquired", 0 ); + player giveweapon( "zombie_tomahawk_flourish" ); + player thread tomahawk_update_hud_on_last_stand(); + player switchtoweapon( "zombie_tomahawk_flourish" ); + player waittill_any( "player_downed", "weapon_change_complete" ); + if ( self.script_noteworthy == "redeemer_pickup_trigger" ) + { + player.redeemer_trigger = self; + player setclientfieldtoplayer( "upgraded_tomahawk_in_use", 1 ); + } + player switchtoweapon( gun ); + player enable_player_move_states(); + player.loadout.hastomahawk = 1; + } + if ( !player hasweapon( "bouncing_tomahawk_zm" ) && !player hasweapon( "upgraded_tomahawk_zm" ) ) + { + player disable_player_move_states( 1 ); + if ( !is_true( player.afterlife ) ) + { + player giveweapon( player.current_tomahawk_weapon ); + player thread tomahawk_update_hud_on_last_stand(); + player thread tomahawk_tutorial_hint(); + player set_player_tactical_grenade( player.current_tomahawk_weapon ); + if ( self.script_noteworthy == "retriever_pickup_trigger" ) + { + player.retriever_trigger = self; + } + player notify( "tomahawk_picked_up" ); + player setclientfieldtoplayer( "tomahawk_in_use", 1 ); + gun = player getcurrentweapon(); + level notify( "bouncing_tomahawk_zm_aquired" ); + player notify( "player_obtained_tomahawk" ); + player maps/mp/zombies/_zm_stats::increment_client_stat( "prison_tomahawk_acquired", 0 ); + player giveweapon( "zombie_tomahawk_flourish" ); + player switchtoweapon( "zombie_tomahawk_flourish" ); + player waittill_any( "player_downed", "weapon_change_complete" ); + if ( self.script_noteworthy == "redeemer_pickup_trigger" ) + { + player setclientfieldtoplayer( "upgraded_tomahawk_in_use", 1 ); + } + player switchtoweapon( gun ); + } + player enable_player_move_states(); + wait 0,1; + } + } +} + +tomahawk_pickup_spin() +{ + self endon( "death" ); + while ( 1 ) + { + self rotateyaw( 90, 1 ); + wait 0,15; + } +} + +calculate_tomahawk_damage( n_target_zombie, n_tomahawk_power, tomahawk ) +{ + if ( n_tomahawk_power > 2 ) + { + return n_target_zombie.health + 1; + } + else + { + if ( level.round_number >= 10 && level.round_number < 13 && tomahawk.low_level_instant_kill_charge <= 3 ) + { + tomahawk.low_level_instant_kill_charge += 1; + return n_target_zombie.health + 1; + } + else + { + if ( level.round_number >= 13 && level.round_number < 15 && tomahawk.low_level_instant_kill_charge <= 2 ) + { + tomahawk.low_level_instant_kill_charge += 1; + return n_target_zombie.health + 1; + } + else + { + return 1000 * n_tomahawk_power; + } + } + } +} + +setting_tutorial_hud() +{ + client_hint = newclienthudelem( self ); + client_hint.alignx = "center"; + client_hint.aligny = "middle"; + client_hint.horzalign = "center"; + client_hint.vertalign = "bottom"; + client_hint.y = -120; + client_hint.foreground = 1; + client_hint.font = "default"; + client_hint.fontscale = 1,5; + client_hint.alpha = 1; + client_hint.color = ( 1, 1, 1 ); + return client_hint; +} + +tomahawk_tutorial_hint() +{ + hud = setting_tutorial_hud(); + hud settext( &"ZM_PRISON_TOMAHAWK_TUTORIAL" ); + self waittill_notify_or_timeout( "throwing_tomahawk", 5 ); + wait 1; + hud destroy(); +} + +tomahawk_update_hud_on_last_stand() +{ + self endon( "disconnect" ); + self endon( "bled_out" ); + self endon( "tomahawk_upgraded_swap" ); + while ( 1 ) + { + self waittill_either( "entering_last_stand", "fake_death" ); + self setclientfieldtoplayer( "tomahawk_in_use", 0 ); + self waittill( "player_revived" ); + if ( isalive( self ) ) + { + wait 0,1; + self setclientfieldtoplayer( "tomahawk_in_use", 1 ); + self giveweapon( self.current_tomahawk_weapon ); + self givemaxammo( self.current_tomahawk_weapon ); + self set_player_tactical_grenade( self.current_tomahawk_weapon ); + } + } +} diff --git a/zm_prison_patch/readme.md b/zm_prison_patch/readme.md index 789822e..718c329 100644 --- a/zm_prison_patch/readme.md +++ b/zm_prison_patch/readme.md @@ -45,7 +45,20 @@ zm_prison_patch/maps/mp/zm_prison_sq_fc.gsc zm_prison_patch/maps/mp/zm_prison_sq_final.gsc zm_prison_patch/maps/mp/zm_prison_sq_wth.gsc - +zm_prison_patch/maps/mp/zombies/_zm_afterlife.gsc +zm_prison_patch/maps/mp/zombies/_zm_ai_brutus.gsc +zm_prison_patch/maps/mp/zombies/_zm_craftables.gsc +zm_prison_patch/maps/mp/zombies/_zm_game_module_grief.gsc +zm_prison_patch/maps/mp/zombies/_zm_game_module_meat.gsc +zm_prison_patch/maps/mp/zombies/_zm_game_module_meat_utility.gsc +zm_prison_patch/maps/mp/zombies/_zm_game_module_utility.gsc +zm_prison_patch/maps/mp/zombies/_zm_magicbox_prison.gsc +zm_prison_patch/maps/mp/zombies/_zm_melee_weapon.gsc +zm_prison_patch/maps/mp/zombies/_zm_riotshield_prison.gsc +zm_prison_patch/maps/mp/zombies/_zm_weap_ballistic_knife.gsc +zm_prison_patch/maps/mp/zombies/_zm_weap_claymore.gsc +zm_prison_patch/maps/mp/zombies/_zm_weap_riotshield_prison.gsc +zm_prison_patch/maps/mp/zombies/_zm_weap_tomahawk.gsc ```