From 7cfed7cdf933706a643d8de2cba5395a44578e39 Mon Sep 17 00:00:00 2001 From: JezuzLizard Date: Wed, 29 Apr 2020 08:29:29 -0700 Subject: [PATCH] uploading all of gametypes_zm as a baseline Starting part 2 of patch_zm checking. --- .../maps/mp/gametypes_zm/_callbacksetup.gsc | 207 ++ .../maps/mp/gametypes_zm/_damagefeedback.gsc | 160 + patch_zm/maps/mp/gametypes_zm/_dev.gsc | 102 + .../maps/mp/gametypes_zm/_gameobjects.gsc | 2668 ++++++++++++++ .../maps/mp/gametypes_zm/_globallogic.gsc | 3101 +++++++++++++++++ .../mp/gametypes_zm/_globallogic_actor.gsc | 207 ++ .../mp/gametypes_zm/_globallogic_audio.gsc | 1034 ++++++ .../mp/gametypes_zm/_globallogic_defaults.gsc | 230 ++ .../mp/gametypes_zm/_globallogic_player.gsc | 2238 ++++++++++++ .../mp/gametypes_zm/_globallogic_score.gsc | 873 +++++ .../mp/gametypes_zm/_globallogic_spawn.gsc | 959 +++++ .../maps/mp/gametypes_zm/_globallogic_ui.gsc | 544 +++ .../mp/gametypes_zm/_globallogic_utils.gsc | 478 +++ .../mp/gametypes_zm/_globallogic_vehicle.gsc | 471 +++ patch_zm/maps/mp/gametypes_zm/_gv_actions.gsc | 995 ++++++ .../maps/mp/gametypes_zm/_healthoverlay.gsc | 288 ++ .../maps/mp/gametypes_zm/_hostmigration.gsc | 546 +++ patch_zm/maps/mp/gametypes_zm/_hud.gsc | 167 + .../maps/mp/gametypes_zm/_hud_message.gsc | 1359 ++++++++ patch_zm/maps/mp/gametypes_zm/_hud_util.gsc | 1152 ++++++ patch_zm/maps/mp/gametypes_zm/_menus.gsc | 175 + patch_zm/maps/mp/gametypes_zm/_perplayer.gsc | 196 ++ .../maps/mp/gametypes_zm/_serversettings.gsc | 207 ++ patch_zm/maps/mp/gametypes_zm/_spawning.gsc | 1073 ++++++ patch_zm/maps/mp/gametypes_zm/_spawnlogic.gsc | 2496 +++++++++++++ patch_zm/maps/mp/gametypes_zm/_spectating.gsc | 276 ++ patch_zm/maps/mp/gametypes_zm/_tweakables.gsc | 394 +++ .../maps/mp/gametypes_zm/_weapon_utils.gsc | 119 + .../maps/mp/gametypes_zm/_weaponobjects.gsc | 2435 +++++++++++++ patch_zm/maps/mp/gametypes_zm/_weapons.gsc | 2029 +++++++++++ 30 files changed, 27179 insertions(+) create mode 100644 patch_zm/maps/mp/gametypes_zm/_callbacksetup.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_damagefeedback.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_dev.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_gameobjects.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic_actor.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic_audio.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic_defaults.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic_player.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic_score.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic_spawn.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic_ui.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic_utils.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_globallogic_vehicle.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_gv_actions.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_healthoverlay.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_hostmigration.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_hud.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_hud_message.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_hud_util.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_menus.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_perplayer.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_serversettings.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_spawning.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_spawnlogic.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_spectating.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_tweakables.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_weapon_utils.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_weaponobjects.gsc create mode 100644 patch_zm/maps/mp/gametypes_zm/_weapons.gsc diff --git a/patch_zm/maps/mp/gametypes_zm/_callbacksetup.gsc b/patch_zm/maps/mp/gametypes_zm/_callbacksetup.gsc new file mode 100644 index 0000000..b96ee03 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_callbacksetup.gsc @@ -0,0 +1,207 @@ +#include maps/mp/gametypes_zm/_hostmigration; +#include maps/mp/gametypes_zm/_globallogic_actor; +#include maps/mp/gametypes_zm/_globallogic_player; +#include maps/mp/gametypes_zm/_globallogic; +#include maps/mp/_audio; +#include maps/mp/_utility; + +codecallback_startgametype() +{ + if ( !isDefined( level.gametypestarted ) || !level.gametypestarted ) + { + [[ level.callbackstartgametype ]](); + level.gametypestarted = 1; + } +} + +codecallback_finalizeinitialization() +{ + maps/mp/_utility::callback( "on_finalize_initialization" ); +} + +codecallback_playerconnect() +{ + self endon( "disconnect" ); + self thread maps/mp/_audio::monitor_player_sprint(); + [[ level.callbackplayerconnect ]](); +} + +codecallback_playerdisconnect() +{ + self notify( "disconnect" ); + client_num = self getentitynumber(); + [[ level.callbackplayerdisconnect ]](); +} + +codecallback_hostmigration() +{ +/# + println( "****CodeCallback_HostMigration****" ); +#/ + [[ level.callbackhostmigration ]](); +} + +codecallback_hostmigrationsave() +{ +/# + println( "****CodeCallback_HostMigrationSave****" ); +#/ + [[ level.callbackhostmigrationsave ]](); +} + +codecallback_prehostmigrationsave() +{ +/# + println( "****CodeCallback_PreHostMigrationSave****" ); +#/ + [[ level.callbackprehostmigrationsave ]](); +} + +codecallback_playermigrated() +{ +/# + println( "****CodeCallback_PlayerMigrated****" ); +#/ + [[ level.callbackplayermigrated ]](); +} + +codecallback_playerdamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, timeoffset, boneindex ) +{ + self endon( "disconnect" ); + [[ level.callbackplayerdamage ]]( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, timeoffset, boneindex ); +} + +codecallback_playerkilled( einflictor, eattacker, idamage, smeansofdeath, sweapon, vdir, shitloc, timeoffset, deathanimduration ) +{ + self endon( "disconnect" ); + [[ level.callbackplayerkilled ]]( einflictor, eattacker, idamage, smeansofdeath, sweapon, vdir, shitloc, timeoffset, deathanimduration ); +} + +codecallback_playerlaststand( einflictor, eattacker, idamage, smeansofdeath, sweapon, vdir, shitloc, timeoffset, deathanimduration ) +{ + self endon( "disconnect" ); + [[ level.callbackplayerlaststand ]]( einflictor, eattacker, idamage, smeansofdeath, sweapon, vdir, shitloc, timeoffset, deathanimduration ); +} + +codecallback_playermelee( eattacker, idamage, sweapon, vorigin, vdir, boneindex, shieldhit ) +{ + self endon( "disconnect" ); + [[ level.callbackplayermelee ]]( eattacker, idamage, sweapon, vorigin, vdir, boneindex, shieldhit ); +} + +codecallback_actordamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, timeoffset, boneindex ) +{ + [[ level.callbackactordamage ]]( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, timeoffset, boneindex ); +} + +codecallback_actorkilled( einflictor, eattacker, idamage, smeansofdeath, sweapon, vdir, shitloc, timeoffset ) +{ + [[ level.callbackactorkilled ]]( einflictor, eattacker, idamage, smeansofdeath, sweapon, vdir, shitloc, timeoffset ); +} + +codecallback_vehicledamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, timeoffset, damagefromunderneath, modelindex, partname ) +{ + [[ level.callbackvehicledamage ]]( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, timeoffset, damagefromunderneath, modelindex, partname ); +} + +codecallback_vehicleradiusdamage( einflictor, eattacker, idamage, finnerdamage, fouterdamage, idflags, smeansofdeath, sweapon, vpoint, fradius, fconeanglecos, vconedir, timeoffset ) +{ +} + +codecallback_faceeventnotify( notify_msg, ent ) +{ + if ( isDefined( ent ) && isDefined( ent.do_face_anims ) && ent.do_face_anims ) + { + if ( isDefined( level.face_event_handler ) && isDefined( level.face_event_handler.events[ notify_msg ] ) ) + { + ent sendfaceevent( level.face_event_handler.events[ notify_msg ] ); + } + } +} + +codecallback_menuresponse( action, arg ) +{ + if ( !isDefined( level.menuresponsequeue ) ) + { + level.menuresponsequeue = []; + level thread menuresponsequeuepump(); + } + index = level.menuresponsequeue.size; + level.menuresponsequeue[ index ] = spawnstruct(); + level.menuresponsequeue[ index ].action = action; + level.menuresponsequeue[ index ].arg = arg; + level.menuresponsequeue[ index ].ent = self; + level notify( "menuresponse_queue" ); +} + +menuresponsequeuepump() +{ + while ( 1 ) + { + level waittill( "menuresponse_queue" ); + level.menuresponsequeue[ 0 ].ent notify( "menuresponse" ); + arrayremoveindex( level.menuresponsequeue, 0, 0 ); + wait 0,05; + } +} + +setupcallbacks() +{ + setdefaultcallbacks(); + level.idflags_radius = 1; + level.idflags_no_armor = 2; + level.idflags_no_knockback = 4; + level.idflags_penetration = 8; + level.idflags_destructible_entity = 16; + level.idflags_shield_explosive_impact = 32; + level.idflags_shield_explosive_impact_huge = 64; + level.idflags_shield_explosive_splash = 128; + level.idflags_no_team_protection = 256; + level.idflags_no_protection = 512; + level.idflags_passthru = 1024; +} + +setdefaultcallbacks() +{ + level.callbackstartgametype = ::maps/mp/gametypes_zm/_globallogic::callback_startgametype; + level.callbackplayerconnect = ::maps/mp/gametypes_zm/_globallogic_player::callback_playerconnect; + level.callbackplayerdisconnect = ::maps/mp/gametypes_zm/_globallogic_player::callback_playerdisconnect; + level.callbackplayerdamage = ::maps/mp/gametypes_zm/_globallogic_player::callback_playerdamage; + level.callbackplayerkilled = ::maps/mp/gametypes_zm/_globallogic_player::callback_playerkilled; + level.callbackplayermelee = ::maps/mp/gametypes_zm/_globallogic_player::callback_playermelee; + level.callbackplayerlaststand = ::maps/mp/gametypes_zm/_globallogic_player::callback_playerlaststand; + level.callbackactordamage = ::maps/mp/gametypes_zm/_globallogic_actor::callback_actordamage; + level.callbackactorkilled = ::maps/mp/gametypes_zm/_globallogic_actor::callback_actorkilled; + level.callbackplayermigrated = ::maps/mp/gametypes_zm/_globallogic_player::callback_playermigrated; + level.callbackhostmigration = ::maps/mp/gametypes_zm/_hostmigration::callback_hostmigration; + level.callbackhostmigrationsave = ::maps/mp/gametypes_zm/_hostmigration::callback_hostmigrationsave; + level.callbackprehostmigrationsave = ::maps/mp/gametypes_zm/_hostmigration::callback_prehostmigrationsave; +} + +abortlevel() +{ +/# + println( "ERROR: Aborting level - gametype is not supported" ); +#/ + level.callbackstartgametype = ::callbackvoid; + level.callbackplayerconnect = ::callbackvoid; + level.callbackplayerdisconnect = ::callbackvoid; + level.callbackplayerdamage = ::callbackvoid; + level.callbackplayerkilled = ::callbackvoid; + level.callbackplayermelee = ::callbackvoid; + level.callbackplayerlaststand = ::callbackvoid; + level.callbackactordamage = ::callbackvoid; + level.callbackactorkilled = ::callbackvoid; + level.callbackvehicledamage = ::callbackvoid; + setdvar( "g_gametype", "dm" ); + exitlevel( 0 ); +} + +codecallback_glasssmash( pos, dir ) +{ + level notify( "glass_smash" ); +} + +callbackvoid() +{ +} diff --git a/patch_zm/maps/mp/gametypes_zm/_damagefeedback.gsc b/patch_zm/maps/mp/gametypes_zm/_damagefeedback.gsc new file mode 100644 index 0000000..5bf5a09 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_damagefeedback.gsc @@ -0,0 +1,160 @@ + +init() +{ + precacheshader( "damage_feedback" ); + precacheshader( "damage_feedback_flak" ); + precacheshader( "damage_feedback_tac" ); + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player.hud_damagefeedback = newdamageindicatorhudelem( player ); + player.hud_damagefeedback.horzalign = "center"; + player.hud_damagefeedback.vertalign = "middle"; + player.hud_damagefeedback.x = -12; + player.hud_damagefeedback.y = -12; + player.hud_damagefeedback.alpha = 0; + player.hud_damagefeedback.archived = 1; + player.hud_damagefeedback setshader( "damage_feedback", 24, 48 ); + player.hitsoundtracker = 1; + } +} + +updatedamagefeedback( mod, inflictor, perkfeedback ) +{ + if ( !isplayer( self ) || sessionmodeiszombiesgame() ) + { + return; + } + if ( isDefined( mod ) && mod != "MOD_CRUSH" && mod != "MOD_GRENADE_SPLASH" && mod != "MOD_HIT_BY_OBJECT" ) + { + if ( isDefined( inflictor ) && isDefined( inflictor.soundmod ) ) + { + switch( inflictor.soundmod ) + { + case "player": + self thread playhitsound( mod, "mpl_hit_alert" ); + break; + case "heli": + self thread playhitsound( mod, "mpl_hit_alert_air" ); + break; + case "hpm": + self thread playhitsound( mod, "mpl_hit_alert_hpm" ); + break; + case "taser_spike": + self thread playhitsound( mod, "mpl_hit_alert_taser_spike" ); + break; + case "dog": + case "straferun": + case "default_loud": + self thread playhitsound( mod, "mpl_hit_heli_gunner" ); + break; + default: + self thread playhitsound( mod, "mpl_hit_alert_low" ); + break; + } + } + else self thread playhitsound( mod, "mpl_hit_alert_low" ); + } + if ( isDefined( perkfeedback ) ) + { + switch( perkfeedback ) + { + case "flakjacket": + self.hud_damagefeedback setshader( "damage_feedback_flak", 24, 48 ); + break; + case "tacticalMask": + self.hud_damagefeedback setshader( "damage_feedback_tac", 24, 48 ); + break; + } + } + else self.hud_damagefeedback setshader( "damage_feedback", 24, 48 ); + self.hud_damagefeedback.alpha = 1; + self.hud_damagefeedback fadeovertime( 1 ); + self.hud_damagefeedback.alpha = 0; + } +} + +playhitsound( mod, alert ) +{ + self endon( "disconnect" ); + if ( self.hitsoundtracker ) + { + self.hitsoundtracker = 0; + self playlocalsound( alert ); + wait 0,05; + self.hitsoundtracker = 1; + } +} + +updatespecialdamagefeedback( hitent ) +{ + if ( !isplayer( self ) ) + { + return; + } + if ( !isDefined( hitent ) ) + { + return; + } + if ( !isplayer( hitent ) ) + { + return; + } + wait 0,05; + if ( !isDefined( self.directionalhitarray ) ) + { + self.directionalhitarray = []; + hitentnum = hitent getentitynumber(); + self.directionalhitarray[ hitentnum ] = 1; + self thread sendhitspecialeventatframeend( hitent ); + } + else + { + hitentnum = hitent getentitynumber(); + self.directionalhitarray[ hitentnum ] = 1; + } +} + +sendhitspecialeventatframeend( hitent ) +{ + self endon( "disconnect" ); + waittillframeend; + enemyshit = 0; + value = 1; + entbitarray0 = 0; + i = 0; + while ( i < 32 ) + { + if ( isDefined( self.directionalhitarray[ i ] ) && self.directionalhitarray[ i ] != 0 ) + { + entbitarray0 += value; + enemyshit++; + } + value *= 2; + i++; + } + entbitarray1 = 0; + i = 33; + while ( i < 64 ) + { + if ( isDefined( self.directionalhitarray[ i ] ) && self.directionalhitarray[ i ] != 0 ) + { + entbitarray1 += value; + enemyshit++; + } + value *= 2; + i++; + } + if ( enemyshit ) + { + self directionalhitindicator( entbitarray0, entbitarray1 ); + } + self.directionalhitarray = undefined; + entbitarray0 = 0; + entbitarray1 = 0; +} diff --git a/patch_zm/maps/mp/gametypes_zm/_dev.gsc b/patch_zm/maps/mp/gametypes_zm/_dev.gsc new file mode 100644 index 0000000..86a3a5e --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_dev.gsc @@ -0,0 +1,102 @@ +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ +/# + for ( ;; ) + { + updatedevsettingszm(); + wait 0,5; +#/ + } +} + +updatedevsettingszm() +{ +/# + if ( level.players.size > 0 ) + { + if ( getDvar( "r_streamDumpDistance" ) == "3" ) + { + if ( !isDefined( level.streamdumpteamindex ) ) + { + level.streamdumpteamindex = 0; + } + else + { + level.streamdumpteamindex++; + } + numpoints = 0; + spawnpoints = []; + 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; + if ( level.streamdumpteamindex < level.teams.size ) + { + structs = getstructarray( "initial_spawn", "script_noteworthy" ); + while ( isDefined( structs ) ) + { + _a46 = structs; + _k46 = getFirstArrayKey( _a46 ); + while ( isDefined( _k46 ) ) + { + struct = _a46[ _k46 ]; + while ( isDefined( struct.script_string ) ) + { + tokens = strtok( struct.script_string, " " ); + _a51 = tokens; + _k51 = getFirstArrayKey( _a51 ); + while ( isDefined( _k51 ) ) + { + token = _a51[ _k51 ]; + if ( token == match_string ) + { + spawnpoints[ spawnpoints.size ] = struct; + } + _k51 = getNextArrayKey( _a51, _k51 ); + } + } + _k46 = getNextArrayKey( _a46, _k46 ); + } + } + if ( !isDefined( spawnpoints ) || spawnpoints.size == 0 ) + { + spawnpoints = getstructarray( "initial_spawn_points", "targetname" ); + } + if ( isDefined( spawnpoints ) ) + { + numpoints = spawnpoints.size; + } + } + if ( numpoints == 0 ) + { + setdvar( "r_streamDumpDistance", "0" ); + level.streamdumpteamindex = -1; + return; + } + else + { + averageorigin = ( 0, 0, 0 ); + averageangles = ( 0, 0, 0 ); + _a80 = spawnpoints; + _k80 = getFirstArrayKey( _a80 ); + while ( isDefined( _k80 ) ) + { + spawnpoint = _a80[ _k80 ]; + averageorigin += spawnpoint.origin / numpoints; + averageangles += spawnpoint.angles / numpoints; + _k80 = getNextArrayKey( _a80, _k80 ); + } + level.players[ 0 ] setplayerangles( averageangles ); + level.players[ 0 ] setorigin( averageorigin ); + wait 0,05; + setdvar( "r_streamDumpDistance", "2" ); +#/ + } + } + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_gameobjects.gsc b/patch_zm/maps/mp/gametypes_zm/_gameobjects.gsc new file mode 100644 index 0000000..d5054cd --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_gameobjects.gsc @@ -0,0 +1,2668 @@ +#include maps/mp/gametypes_zm/_tweakables; +#include maps/mp/gametypes_zm/_hostmigration; +#include maps/mp/gametypes_zm/_weapons; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +main( allowed ) +{ + level.vehiclesenabled = getgametypesetting( "vehiclesEnabled" ); + level.vehiclestimed = getgametypesetting( "vehiclesTimed" ); + level.objectivepingdelay = getgametypesetting( "objectivePingTime" ); + level.nonteambasedteam = "allies"; +/# + if ( level.script == "mp_vehicle_test" ) + { + level.vehiclesenabled = 1; +#/ + } + if ( level.vehiclesenabled ) + { + allowed[ allowed.size ] = "vehicle"; + filter_script_vehicles_from_vehicle_descriptors( allowed ); + } + entities = getentarray(); + entity_index = entities.size - 1; + while ( entity_index >= 0 ) + { + entity = entities[ entity_index ]; + if ( !entity_is_allowed( entity, allowed ) ) + { + entity delete(); + } + entity_index--; + + } + return; +} + +entity_is_allowed( entity, allowed_game_modes ) +{ + if ( isDefined( level.createfx_enabled ) && level.createfx_enabled ) + { + return 1; + } + allowed = 1; + while ( isDefined( entity.script_gameobjectname ) && entity.script_gameobjectname != "[all_modes]" ) + { + allowed = 0; + gameobjectnames = strtok( entity.script_gameobjectname, " " ); + i = 0; + while ( i < allowed_game_modes.size && !allowed ) + { + j = 0; + while ( j < gameobjectnames.size && !allowed ) + { + allowed = gameobjectnames[ j ] == allowed_game_modes[ i ]; + j++; + } + i++; + } + } + return allowed; +} + +location_is_allowed( entity, location ) +{ + allowed = 1; + location_list = undefined; + if ( isDefined( entity.script_noteworthy ) ) + { + location_list = entity.script_noteworthy; + } + if ( isDefined( entity.script_location ) ) + { + location_list = entity.script_location; + } + while ( isDefined( location_list ) ) + { + if ( location_list == "[all_modes]" ) + { + allowed = 1; + break; + } + else allowed = 0; + gameobjectlocations = strtok( location_list, " " ); + j = 0; + while ( j < gameobjectlocations.size ) + { + if ( gameobjectlocations[ j ] == location ) + { + allowed = 1; + break; + } + else + { + j++; + } + } + } + return allowed; +} + +filter_script_vehicles_from_vehicle_descriptors( allowed_game_modes ) +{ + vehicle_descriptors = getentarray( "vehicle_descriptor", "targetname" ); + script_vehicles = getentarray( "script_vehicle", "classname" ); + vehicles_to_remove = []; + descriptor_index = 0; + while ( descriptor_index < vehicle_descriptors.size ) + { + descriptor = vehicle_descriptors[ descriptor_index ]; + closest_distance_sq = 1E+12; + closest_vehicle = undefined; + vehicle_index = 0; + while ( vehicle_index < script_vehicles.size ) + { + vehicle = script_vehicles[ vehicle_index ]; + dsquared = distancesquared( vehicle getorigin(), descriptor getorigin() ); + if ( dsquared < closest_distance_sq ) + { + closest_distance_sq = dsquared; + closest_vehicle = vehicle; + } + vehicle_index++; + } + if ( isDefined( closest_vehicle ) ) + { + if ( !entity_is_allowed( descriptor, allowed_game_modes ) ) + { + vehicles_to_remove[ vehicles_to_remove.size ] = closest_vehicle; + } + } + descriptor_index++; + } + vehicle_index = 0; + while ( vehicle_index < vehicles_to_remove.size ) + { + vehicles_to_remove[ vehicle_index ] delete(); + vehicle_index++; + } + return; +} + +init() +{ + level.numgametypereservedobjectives = 0; + level.releasedobjectives = []; + if ( !sessionmodeiszombiesgame() ) + { + precacheitem( "briefcase_bomb_mp" ); + precacheitem( "briefcase_bomb_defuse_mp" ); + } + level thread onplayerconnect(); +} + +onplayerconnect() +{ + level endon( "game_ended" ); + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onplayerspawned(); + player thread ondisconnect(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread ondeath(); + self.touchtriggers = []; + self.carryobject = undefined; + self.claimtrigger = undefined; + self.canpickupobject = 1; + self.disabledweapon = 0; + self.killedinuse = undefined; + } +} + +ondeath() +{ + level endon( "game_ended" ); + self endon( "spawned_player" ); + self waittill( "death" ); + if ( isDefined( self.carryobject ) ) + { + self.carryobject thread setdropped(); + } +} + +ondisconnect() +{ + level endon( "game_ended" ); + self waittill( "disconnect" ); + if ( isDefined( self.carryobject ) ) + { + self.carryobject thread setdropped(); + } +} + +createcarryobject( ownerteam, trigger, visuals, offset, objectivename ) +{ + carryobject = spawnstruct(); + carryobject.type = "carryObject"; + carryobject.curorigin = trigger.origin; + carryobject.ownerteam = ownerteam; + carryobject.entnum = trigger getentitynumber(); + if ( issubstr( trigger.classname, "use" ) ) + { + carryobject.triggertype = "use"; + } + else + { + carryobject.triggertype = "proximity"; + } + trigger.baseorigin = trigger.origin; + carryobject.trigger = trigger; + carryobject.useweapon = undefined; + if ( !isDefined( offset ) ) + { + offset = ( 0, 0, 1 ); + } + carryobject.offset3d = offset; + carryobject.newstyle = 0; + if ( isDefined( objectivename ) ) + { + carryobject.newstyle = 1; + } + else + { + objectivename = &""; + } + index = 0; + while ( index < visuals.size ) + { + visuals[ index ].baseorigin = visuals[ index ].origin; + visuals[ index ].baseangles = visuals[ index ].angles; + index++; + } + carryobject.visuals = visuals; + carryobject.compassicons = []; + carryobject.objid = []; + while ( !carryobject.newstyle ) + { + _a319 = level.teams; + _k319 = getFirstArrayKey( _a319 ); + while ( isDefined( _k319 ) ) + { + team = _a319[ _k319 ]; + carryobject.objid[ team ] = getnextobjid(); + _k319 = getNextArrayKey( _a319, _k319 ); + } + } + carryobject.objidpingfriendly = 0; + carryobject.objidpingenemy = 0; + level.objidstart += 2; + carryobject.objectiveid = getnextobjid(); + objective_add( carryobject.objectiveid, "invisible", carryobject.curorigin, objectivename ); + carryobject.carrier = undefined; + carryobject.isresetting = 0; + carryobject.interactteam = "none"; + carryobject.allowweapons = 0; + carryobject.visiblecarriermodel = undefined; + carryobject.worldicons = []; + carryobject.carriervisible = 0; + carryobject.visibleteam = "none"; + carryobject.worldiswaypoint = []; + carryobject.carryicon = undefined; + carryobject.ondrop = undefined; + carryobject.onpickup = undefined; + carryobject.onreset = undefined; + if ( carryobject.triggertype == "use" ) + { + carryobject thread carryobjectusethink(); + } + else + { + carryobject thread carryobjectproxthink(); + } + carryobject thread updatecarryobjectorigin(); + carryobject thread updatecarryobjectobjectiveorigin(); + return carryobject; +} + +carryobjectusethink() +{ + level endon( "game_ended" ); + self.trigger endon( "destroyed" ); + while ( 1 ) + { + self.trigger waittill( "trigger", player ); + while ( self.isresetting ) + { + continue; + } + while ( !isalive( player ) ) + { + continue; + } + if ( isDefined( player.laststand ) && player.laststand ) + { + continue; + } + while ( !self caninteractwith( player ) ) + { + continue; + } + while ( !player.canpickupobject ) + { + continue; + } + while ( player.throwinggrenade ) + { + continue; + } + while ( isDefined( self.carrier ) ) + { + continue; + } + while ( player isinvehicle() ) + { + continue; + } + while ( player isweaponviewonlylinked() ) + { + continue; + } + while ( !player istouching( self.trigger ) ) + { + continue; + } + self setpickedup( player ); + } +} + +carryobjectproxthink() +{ + level endon( "game_ended" ); + self.trigger endon( "destroyed" ); + while ( 1 ) + { + self.trigger waittill( "trigger", player ); + while ( self.isresetting ) + { + continue; + } + while ( !isalive( player ) ) + { + continue; + } + if ( isDefined( player.laststand ) && player.laststand ) + { + continue; + } + while ( !self caninteractwith( player ) ) + { + continue; + } + while ( !player.canpickupobject ) + { + continue; + } + while ( player.throwinggrenade ) + { + continue; + } + while ( isDefined( self.carrier ) ) + { + continue; + } + while ( player isinvehicle() ) + { + continue; + } + while ( player isweaponviewonlylinked() ) + { + continue; + } + while ( !player istouching( self.trigger ) ) + { + continue; + } + self setpickedup( player ); + } +} + +pickupobjectdelay( origin ) +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "disconnect" ); + self.canpickupobject = 0; + for ( ;; ) + { + if ( distancesquared( self.origin, origin ) > 4096 ) + { + break; + } + else + { + wait 0,2; + } + } + self.canpickupobject = 1; +} + +setpickedup( player ) +{ + if ( isDefined( player.carryobject ) ) + { + if ( isDefined( player.carryobject.swappable ) && player.carryobject.swappable ) + { + player.carryobject thread setdropped(); + } + else + { + if ( isDefined( self.onpickupfailed ) ) + { + self [[ self.onpickupfailed ]]( player ); + } + return; + } + } + player giveobject( self ); + self setcarrier( player ); + index = 0; + while ( index < self.visuals.size ) + { + self.visuals[ index ] thread hideobject(); + index++; + } + self.trigger.origin += vectorScale( ( 0, 0, 1 ), 10000 ); + self notify( "pickup_object" ); + if ( isDefined( self.onpickup ) ) + { + self [[ self.onpickup ]]( player ); + } + self updatecompassicons(); + self updateworldicons(); + self updateobjective(); +} + +hideobject() +{ + radius = 32; + origin = self.origin; + grenades = getentarray( "grenade", "classname" ); + radiussq = radius * radius; + linkedgrenades = []; + linkedgrenadesindex = 0; + self hide(); + i = 0; + while ( i < grenades.size ) + { + if ( distancesquared( origin, grenades[ i ].origin ) < radiussq ) + { + if ( grenades[ i ] islinkedto( self ) ) + { + linkedgrenades[ linkedgrenadesindex ] = grenades[ i ]; + linkedgrenades[ linkedgrenadesindex ] unlink(); + linkedgrenadesindex++; + } + } + i++; + } + self.origin += vectorScale( ( 0, 0, 1 ), 10000 ); + waittillframeend; + i = 0; + while ( i < linkedgrenadesindex ) + { + linkedgrenades[ i ] launch( vectorScale( ( 0, 0, 1 ), 5 ) ); + i++; + } +} + +updatecarryobjectorigin() +{ + level endon( "game_ended" ); + self.trigger endon( "destroyed" ); + if ( self.newstyle ) + { + return; + } + objpingdelay = level.objectivepingdelay; + for ( ;; ) + { + if ( isDefined( self.carrier ) && level.teambased ) + { + self.curorigin = self.carrier.origin + vectorScale( ( 0, 0, 1 ), 75 ); + while ( self.visibleteam != "friendly" && self.visibleteam == "any" && self.objidpingfriendly ) + { + _a626 = level.teams; + _k626 = getFirstArrayKey( _a626 ); + while ( isDefined( _k626 ) ) + { + team = _a626[ _k626 ]; + if ( self isfriendlyteam( team ) ) + { + if ( self.objpoints[ team ].isshown ) + { + self.objpoints[ team ].alpha = self.objpoints[ team ].basealpha; + self.objpoints[ team ] fadeovertime( objpingdelay + 1 ); + self.objpoints[ team ].alpha = 0; + } + objective_position( self.objid[ team ], self.curorigin ); + } + _k626 = getNextArrayKey( _a626, _k626 ); + } + } + if ( self.visibleteam != "enemy" && self.visibleteam == "any" && self.objidpingenemy ) + { + if ( !self isfriendlyteam( team ) ) + { + if ( self.objpoints[ team ].isshown ) + { + self.objpoints[ team ].alpha = self.objpoints[ team ].basealpha; + self.objpoints[ team ] fadeovertime( objpingdelay + 1 ); + self.objpoints[ team ].alpha = 0; + } + objective_position( self.objid[ team ], self.curorigin ); + } + } + self wait_endon( objpingdelay, "dropped", "reset" ); + continue; + } + else + { + if ( isDefined( self.carrier ) ) + { + self.curorigin = self.carrier.origin + vectorScale( ( 0, 0, 1 ), 75 ); + wait 0,05; + break; + } + else + { + wait 0,05; + } + } + } +} + +updatecarryobjectobjectiveorigin() +{ + level endon( "game_ended" ); + self.trigger endon( "destroyed" ); + if ( !self.newstyle ) + { + return; + } + objpingdelay = level.objectivepingdelay; + for ( ;; ) + { + if ( isDefined( self.carrier ) ) + { + self.curorigin = self.carrier.origin; + objective_position( self.objectiveid, self.curorigin ); + self wait_endon( objpingdelay, "dropped", "reset" ); + continue; + } + else + { + objective_position( self.objectiveid, self.curorigin ); + wait 0,05; + } + } +} + +giveobject( object ) +{ +/# + assert( !isDefined( self.carryobject ) ); +#/ + self.carryobject = object; + self thread trackcarrier(); + if ( !object.allowweapons ) + { + self _disableweapon(); + self thread manualdropthink(); + } + self.disallowvehicleusage = 1; + if ( isDefined( object.visiblecarriermodel ) ) + { + self maps/mp/gametypes_zm/_weapons::forcestowedweaponupdate(); + } + if ( !object.newstyle ) + { + if ( isDefined( object.carryicon ) ) + { + if ( self issplitscreen() ) + { + self.carryicon = createicon( object.carryicon, 35, 35 ); + self.carryicon.x = -130; + self.carryicon.y = -90; + self.carryicon.horzalign = "right"; + self.carryicon.vertalign = "bottom"; + } + else self.carryicon = createicon( object.carryicon, 50, 50 ); + if ( !object.allowweapons ) + { + self.carryicon setpoint( "CENTER", "CENTER", 0, 60 ); + } + else + { + self.carryicon.x = 130; + self.carryicon.y = -60; + self.carryicon.horzalign = "user_left"; + self.carryicon.vertalign = "user_bottom"; + } + self.carryicon.alpha = 0,75; + self.carryicon.hidewhileremotecontrolling = 1; + self.carryicon.hidewheninkillcam = 1; + } + } +} + +returnhome() +{ + self.isresetting = 1; + self notify( "reset" ); + index = 0; + while ( index < self.visuals.size ) + { + self.visuals[ index ].origin = self.visuals[ index ].baseorigin; + self.visuals[ index ].angles = self.visuals[ index ].baseangles; + self.visuals[ index ] show(); + index++; + } + self.trigger.origin = self.trigger.baseorigin; + self.curorigin = self.trigger.origin; + if ( isDefined( self.onreset ) ) + { + self [[ self.onreset ]](); + } + self clearcarrier(); + updateworldicons(); + updatecompassicons(); + updateobjective(); + self.isresetting = 0; +} + +isobjectawayfromhome() +{ + if ( isDefined( self.carrier ) ) + { + return 1; + } + if ( distancesquared( self.trigger.origin, self.trigger.baseorigin ) > 4 ) + { + return 1; + } + return 0; +} + +setposition( origin, angles ) +{ + self.isresetting = 1; + index = 0; + while ( index < self.visuals.size ) + { + visual = self.visuals[ index ]; + visual.origin = origin; + visual.angles = angles; + visual show(); + index++; + } + self.trigger.origin = origin; + self.curorigin = self.trigger.origin; + self clearcarrier(); + updateworldicons(); + updatecompassicons(); + updateobjective(); + self.isresetting = 0; +} + +onplayerlaststand() +{ + if ( isDefined( self.carryobject ) ) + { + self.carryobject thread setdropped(); + } +} + +setdropped() +{ + self.isresetting = 1; + self notify( "dropped" ); + startorigin = ( 0, 0, 1 ); + endorigin = ( 0, 0, 1 ); + body = undefined; + if ( isDefined( self.carrier ) && self.carrier.team != "spectator" ) + { + startorigin = self.carrier.origin + vectorScale( ( 0, 0, 1 ), 20 ); + endorigin = self.carrier.origin - vectorScale( ( 0, 0, 1 ), 2000 ); + body = self.carrier.body; + self.visuals[ 0 ].origin = self.carrier.origin; + } + else + { + startorigin = self.safeorigin + vectorScale( ( 0, 0, 1 ), 20 ); + endorigin = self.safeorigin - vectorScale( ( 0, 0, 1 ), 20 ); + } + trace = playerphysicstrace( startorigin, endorigin ); + angletrace = bullettrace( startorigin, endorigin, 0, body ); + droppingplayer = self.carrier; + if ( isDefined( trace ) ) + { + tempangle = randomfloat( 360 ); + droporigin = trace; + if ( angletrace[ "fraction" ] < 1 && distance( angletrace[ "position" ], trace ) < 10 ) + { + forward = ( cos( tempangle ), sin( tempangle ), 0 ); + forward = vectornormalize( forward - vectorScale( angletrace[ "normal" ], vectordot( forward, angletrace[ "normal" ] ) ) ); + dropangles = vectorToAngle( forward ); + } + else + { + dropangles = ( 0, tempangle, 0 ); + } + index = 0; + while ( index < self.visuals.size ) + { + self.visuals[ index ].origin = droporigin; + self.visuals[ index ].angles = dropangles; + self.visuals[ index ] show(); + index++; + } + self.trigger.origin = droporigin; + self.curorigin = self.trigger.origin; + self thread pickuptimeout( trace[ 2 ], startorigin[ 2 ] ); + } + else + { + index = 0; + while ( index < self.visuals.size ) + { + self.visuals[ index ].origin = self.visuals[ index ].baseorigin; + self.visuals[ index ].angles = self.visuals[ index ].baseangles; + self.visuals[ index ] show(); + index++; + } + self.trigger.origin = self.trigger.baseorigin; + self.curorigin = self.trigger.baseorigin; + } + if ( isDefined( self.ondrop ) ) + { + self [[ self.ondrop ]]( droppingplayer ); + } + self clearcarrier(); + self updatecompassicons(); + self updateworldicons(); + self updateobjective(); + self.isresetting = 0; +} + +setcarrier( carrier ) +{ + self.carrier = carrier; + objective_setplayerusing( self.objectiveid, carrier ); + self thread updatevisibilityaccordingtoradar(); +} + +clearcarrier() +{ + if ( !isDefined( self.carrier ) ) + { + return; + } + self.carrier takeobject( self ); + objective_clearplayerusing( self.objectiveid, self.carrier ); + self.carrier = undefined; + self notify( "carrier_cleared" ); +} + +shouldbereset( minz, maxz ) +{ + minetriggers = getentarray( "minefield", "targetname" ); + hurttriggers = getentarray( "trigger_hurt", "classname" ); + elevators = getentarray( "script_elevator", "targetname" ); + index = 0; + while ( index < minetriggers.size ) + { + if ( self.visuals[ 0 ] istouchingswept( minetriggers[ index ], minz, maxz ) ) + { + return 1; + } + index++; + } + index = 0; + while ( index < hurttriggers.size ) + { + if ( self.visuals[ 0 ] istouchingswept( hurttriggers[ index ], minz, maxz ) ) + { + return 1; + } + index++; + } + index = 0; + while ( index < elevators.size ) + { +/# + assert( isDefined( elevators[ index ].occupy_volume ) ); +#/ + if ( self.visuals[ 0 ] istouchingswept( elevators[ index ].occupy_volume, minz, maxz ) ) + { + return 1; + } + index++; + } + return 0; +} + +pickuptimeout( minz, maxz ) +{ + self endon( "pickup_object" ); + self endon( "stop_pickup_timeout" ); + wait 0,05; + if ( self shouldbereset( minz, maxz ) ) + { + self returnhome(); + return; + } + if ( isDefined( self.autoresettime ) ) + { + wait self.autoresettime; + if ( !isDefined( self.carrier ) ) + { + self returnhome(); + } + } +} + +takeobject( object ) +{ + if ( isDefined( self.carryicon ) ) + { + self.carryicon destroyelem(); + } + if ( isDefined( object.visiblecarriermodel ) ) + { + self maps/mp/gametypes_zm/_weapons::detach_all_weapons(); + } + self.carryobject = undefined; + if ( !isalive( self ) ) + { + return; + } + self notify( "drop_object" ); + self.disallowvehicleusage = 0; + if ( object.triggertype == "proximity" ) + { + self thread pickupobjectdelay( object.trigger.origin ); + } + if ( isDefined( object.visiblecarriermodel ) ) + { + self maps/mp/gametypes_zm/_weapons::forcestowedweaponupdate(); + } + if ( !object.allowweapons ) + { + self _enableweapon(); + } +} + +trackcarrier() +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + self endon( "death" ); + self endon( "drop_object" ); + while ( isDefined( self.carryobject ) && isalive( self ) ) + { + if ( self isonground() ) + { + trace = bullettrace( self.origin + vectorScale( ( 0, 0, 1 ), 20 ), self.origin - vectorScale( ( 0, 0, 1 ), 20 ), 0, undefined ); + if ( trace[ "fraction" ] < 1 ) + { + self.carryobject.safeorigin = trace[ "position" ]; + } + } + wait 0,05; + } +} + +manualdropthink() +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + self endon( "death" ); + self endon( "drop_object" ); + for ( ;; ) + { + while ( !self attackbuttonpressed() && !self fragbuttonpressed() || self secondaryoffhandbuttonpressed() && self meleebuttonpressed() ) + { + wait 0,05; + } + while ( !self attackbuttonpressed() && !self fragbuttonpressed() && !self secondaryoffhandbuttonpressed() && !self meleebuttonpressed() ) + { + wait 0,05; + } + if ( isDefined( self.carryobject ) && !self usebuttonpressed() ) + { + self.carryobject thread setdropped(); + } + } +} + +createuseobject( ownerteam, trigger, visuals, offset, objectivename ) +{ + useobject = spawnstruct(); + useobject.type = "useObject"; + useobject.curorigin = trigger.origin; + useobject.ownerteam = ownerteam; + useobject.entnum = trigger getentitynumber(); + useobject.keyobject = undefined; + if ( issubstr( trigger.classname, "use" ) ) + { + useobject.triggertype = "use"; + } + else + { + useobject.triggertype = "proximity"; + } + useobject.trigger = trigger; + index = 0; + while ( index < visuals.size ) + { + visuals[ index ].baseorigin = visuals[ index ].origin; + visuals[ index ].baseangles = visuals[ index ].angles; + index++; + } + useobject.visuals = visuals; + if ( !isDefined( offset ) ) + { + offset = ( 0, 0, 1 ); + } + useobject.offset3d = offset; + useobject.newstyle = 0; + if ( isDefined( objectivename ) ) + { + useobject.newstyle = 1; + } + else + { + objectivename = &""; + } + useobject.compassicons = []; + useobject.objid = []; + if ( !useobject.newstyle ) + { + _a1185 = level.teams; + _k1185 = getFirstArrayKey( _a1185 ); + while ( isDefined( _k1185 ) ) + { + team = _a1185[ _k1185 ]; + useobject.objid[ team ] = getnextobjid(); + _k1185 = getNextArrayKey( _a1185, _k1185 ); + } + if ( level.teambased ) + { + _a1192 = level.teams; + _k1192 = getFirstArrayKey( _a1192 ); + while ( isDefined( _k1192 ) ) + { + team = _a1192[ _k1192 ]; + objective_add( useobject.objid[ team ], "invisible", useobject.curorigin ); + objective_team( useobject.objid[ team ], team ); + _k1192 = getNextArrayKey( _a1192, _k1192 ); + } + } + else objective_add( useobject.objid[ level.nonteambasedteam ], "invisible", useobject.curorigin ); + } + useobject.objectiveid = getnextobjid(); + objective_add( useobject.objectiveid, "invisible", useobject.curorigin, objectivename ); + useobject.interactteam = "none"; + useobject.worldicons = []; + useobject.visibleteam = "none"; + useobject.worldiswaypoint = []; + useobject.onuse = undefined; + useobject.oncantuse = undefined; + useobject.usetext = "default"; + useobject.usetime = 10000; + useobject clearprogress(); + useobject.decayprogress = 0; + if ( useobject.triggertype == "proximity" ) + { + useobject.numtouching[ "neutral" ] = 0; + useobject.numtouching[ "none" ] = 0; + useobject.touchlist[ "neutral" ] = []; + useobject.touchlist[ "none" ] = []; + _a1255 = level.teams; + _k1255 = getFirstArrayKey( _a1255 ); + while ( isDefined( _k1255 ) ) + { + team = _a1255[ _k1255 ]; + useobject.numtouching[ team ] = 0; + useobject.touchlist[ team ] = []; + _k1255 = getNextArrayKey( _a1255, _k1255 ); + } + useobject.userate = 0; + useobject.claimteam = "none"; + useobject.claimplayer = undefined; + useobject.lastclaimteam = "none"; + useobject.lastclaimtime = 0; + useobject.claimgraceperiod = 1; + useobject.mustmaintainclaim = 0; + useobject.cancontestclaim = 0; + useobject thread useobjectproxthink(); + } + else + { + useobject.userate = 1; + useobject thread useobjectusethink(); + } + return useobject; +} + +setkeyobject( object ) +{ + if ( !isDefined( object ) ) + { + self.keyobject = undefined; + return; + } + if ( !isDefined( self.keyobject ) ) + { + self.keyobject = []; + } + self.keyobject[ self.keyobject.size ] = object; +} + +haskeyobject( use ) +{ + x = 0; + while ( x < use.keyobject.size ) + { + if ( isDefined( self.carryobject ) && isDefined( use.keyobject[ x ] ) && self.carryobject == use.keyobject[ x ] ) + { + return 1; + } + x++; + } + return 0; +} + +useobjectusethink() +{ + level endon( "game_ended" ); + self.trigger endon( "destroyed" ); + while ( 1 ) + { + self.trigger waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( !self caninteractwith( player ) ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + while ( player isinvehicle() ) + { + continue; + } + while ( isDefined( self.keyobject ) || !isDefined( player.carryobject ) && !player haskeyobject( self ) ) + { + if ( isDefined( self.oncantuse ) ) + { + self [[ self.oncantuse ]]( player ); + } + } + result = 1; + if ( self.usetime > 0 ) + { + if ( isDefined( self.onbeginuse ) ) + { + self [[ self.onbeginuse ]]( player ); + } + team = player.pers[ "team" ]; + result = self useholdthink( player ); + if ( isDefined( self.onenduse ) ) + { + self [[ self.onenduse ]]( team, player, result ); + } + } + while ( !result ) + { + continue; + } + if ( isDefined( self.onuse ) ) + { + self [[ self.onuse ]]( player ); + } + } +} + +getearliestclaimplayer() +{ +/# + assert( self.claimteam != "none" ); +#/ + team = self.claimteam; + earliestplayer = self.claimplayer; + while ( self.touchlist[ team ].size > 0 ) + { + earliesttime = undefined; + players = getarraykeys( self.touchlist[ team ] ); + index = 0; + while ( index < players.size ) + { + touchdata = self.touchlist[ team ][ players[ index ] ]; + if ( !isDefined( earliesttime ) || touchdata.starttime < earliesttime ) + { + earliestplayer = touchdata.player; + earliesttime = touchdata.starttime; + } + index++; + } + } + return earliestplayer; +} + +useobjectproxthink() +{ + level endon( "game_ended" ); + self.trigger endon( "destroyed" ); + self thread proxtriggerthink(); + while ( 1 ) + { + if ( self.usetime && self.curprogress >= self.usetime ) + { + self clearprogress(); + creditplayer = getearliestclaimplayer(); + if ( isDefined( self.onenduse ) ) + { + self [[ self.onenduse ]]( self getclaimteam(), creditplayer, isDefined( creditplayer ) ); + } + if ( isDefined( creditplayer ) && isDefined( self.onuse ) ) + { + self [[ self.onuse ]]( creditplayer ); + } + self setclaimteam( "none" ); + self.claimplayer = undefined; + } + if ( self.claimteam != "none" ) + { + if ( self useobjectlockedforteam( self.claimteam ) ) + { + if ( isDefined( self.onenduse ) ) + { + self [[ self.onenduse ]]( self getclaimteam(), self.claimplayer, 0 ); + } + self setclaimteam( "none" ); + self.claimplayer = undefined; + self clearprogress(); + } + else if ( self.usetime ) + { + if ( self.decayprogress && !self.numtouching[ self.claimteam ] ) + { + if ( isDefined( self.claimplayer ) ) + { + if ( isDefined( self.onenduse ) ) + { + self [[ self.onenduse ]]( self getclaimteam(), self.claimplayer, 0 ); + } + self.claimplayer = undefined; + } + decayscale = 0; + if ( self.decaytime ) + { + decayscale = self.usetime / self.decaytime; + } + self.curprogress -= 50 * self.userate * decayscale; + if ( self.curprogress <= 0 ) + { + self clearprogress(); + } + self updatecurrentprogress(); + if ( isDefined( self.onuseupdate ) ) + { + self [[ self.onuseupdate ]]( self getclaimteam(), self.curprogress / self.usetime, ( 50 * self.userate * decayscale ) / self.usetime ); + } + if ( self.curprogress == 0 ) + { + self setclaimteam( "none" ); + } + } + else + { + if ( !self.numtouching[ self.claimteam ] ) + { + if ( isDefined( self.onenduse ) ) + { + self [[ self.onenduse ]]( self getclaimteam(), self.claimplayer, 0 ); + } + self setclaimteam( "none" ); + self.claimplayer = undefined; + break; + } + else + { + self.curprogress += 50 * self.userate; + self updatecurrentprogress(); + if ( isDefined( self.onuseupdate ) ) + { + self [[ self.onuseupdate ]]( self getclaimteam(), self.curprogress / self.usetime, ( 50 * self.userate ) / self.usetime ); + } + } + } + } + else if ( !self.mustmaintainclaim ) + { + if ( isDefined( self.onuse ) ) + { + self [[ self.onuse ]]( self.claimplayer ); + } + if ( !self.mustmaintainclaim ) + { + self setclaimteam( "none" ); + self.claimplayer = undefined; + } + } + else if ( !self.numtouching[ self.claimteam ] ) + { + if ( isDefined( self.onunoccupied ) ) + { + self [[ self.onunoccupied ]](); + } + self setclaimteam( "none" ); + self.claimplayer = undefined; + } + else + { + if ( self.cancontestclaim ) + { + numother = getnumtouchingexceptteam( self.claimteam ); + if ( numother > 0 ) + { + if ( isDefined( self.oncontested ) ) + { + self [[ self.oncontested ]](); + } + self setclaimteam( "none" ); + self.claimplayer = undefined; + } + } + } + } + else + { + if ( self.curprogress > 0 && ( getTime() - self.lastclaimtime ) > ( self.claimgraceperiod * 1000 ) ) + { + self clearprogress(); + } + } + wait 0,05; + maps/mp/gametypes_zm/_hostmigration::waittillhostmigrationdone(); + } +} + +useobjectlockedforteam( team ) +{ + if ( isDefined( self.teamlock ) && isDefined( level.teams[ team ] ) ) + { + return self.teamlock[ team ]; + } + return 0; +} + +canclaim( player ) +{ + if ( self.cancontestclaim ) + { + numother = getnumtouchingexceptteam( player.pers[ "team" ] ); + if ( numother != 0 ) + { + return 0; + } + } + if ( !isDefined( self.keyobject ) || isDefined( player.carryobject ) && player haskeyobject( self ) ) + { + return 1; + } + return 0; +} + +proxtriggerthink() +{ + level endon( "game_ended" ); + self.trigger endon( "destroyed" ); + entitynumber = self.entnum; + while ( 1 ) + { + self.trigger waittill( "trigger", player ); + if ( !isalive( player ) || self useobjectlockedforteam( player.pers[ "team" ] ) ) + { + continue; + } + while ( player isinvehicle() ) + { + continue; + } + while ( player isweaponviewonlylinked() ) + { + continue; + } + if ( self caninteractwith( player ) && self.claimteam == "none" ) + { + if ( self canclaim( player ) ) + { + setclaimteam( player.pers[ "team" ] ); + self.claimplayer = player; + if ( self.usetime && isDefined( self.onbeginuse ) ) + { + self [[ self.onbeginuse ]]( self.claimplayer ); + } + break; + } + else + { + if ( isDefined( self.oncantuse ) ) + { + self [[ self.oncantuse ]]( player ); + } + } + } + if ( isalive( player ) && !isDefined( player.touchtriggers[ entitynumber ] ) ) + { + player thread triggertouchthink( self ); + } + } +} + +clearprogress() +{ + self.curprogress = 0; + self updatecurrentprogress(); + if ( isDefined( self.onuseclear ) ) + { + self [[ self.onuseclear ]](); + } +} + +setclaimteam( newteam ) +{ +/# + assert( newteam != self.claimteam ); +#/ + if ( self.claimteam == "none" && ( getTime() - self.lastclaimtime ) > ( self.claimgraceperiod * 1000 ) ) + { + self clearprogress(); + } + else + { + if ( newteam != "none" && newteam != self.lastclaimteam ) + { + self clearprogress(); + } + } + self.lastclaimteam = self.claimteam; + self.lastclaimtime = getTime(); + self.claimteam = newteam; + self updateuserate(); +} + +getclaimteam() +{ + return self.claimteam; +} + +continuetriggertouchthink( team, object ) +{ + if ( !isalive( self ) ) + { + return 0; + } + if ( self useobjectlockedforteam( team ) ) + { + return 0; + } + if ( self isinvehicle() ) + { + return 0; + } + if ( !self istouching( object.trigger ) ) + { + return 0; + } + return 1; +} + +triggertouchthink( object ) +{ + team = self.pers[ "team" ]; + score = 1; + object.numtouching[ team ] += score; + if ( object.usetime ) + { + object updateuserate(); + } + touchname = "player" + self.clientid; + struct = spawnstruct(); + struct.player = self; + struct.starttime = getTime(); + object.touchlist[ team ][ touchname ] = struct; + objective_setplayerusing( object.objectiveid, self ); + self.touchtriggers[ object.entnum ] = object.trigger; + if ( isDefined( object.ontouchuse ) ) + { + object [[ object.ontouchuse ]]( self ); + } + while ( self continuetriggertouchthink( team, object ) ) + { + if ( object.usetime ) + { + self updateproxbar( object, 0 ); + } + wait 0,05; + } + if ( isDefined( self ) ) + { + if ( object.usetime ) + { + self updateproxbar( object, 1 ); + } + objective_clearplayerusing( object.objectiveid, self ); + } + if ( level.gameended ) + { + return; + } + object.numtouching[ team ] -= score; + if ( object.numtouching[ team ] < 1 ) + { + object.numtouching[ team ] = 0; + } + if ( object.usetime ) + { + if ( object.numtouching[ team ] <= 0 && object.curprogress >= object.usetime ) + { + object.curprogress = object.usetime - 1; + object updatecurrentprogress(); + } + } + if ( isDefined( self ) && isDefined( object.onendtouchuse ) ) + { + object [[ object.onendtouchuse ]]( self ); + } + object updateuserate(); +} + +updateproxbar( object, forceremove ) +{ + if ( object.newstyle ) + { + return; + } + if ( !forceremove && object.decayprogress ) + { + if ( !object caninteractwith( self ) ) + { + if ( isDefined( self.proxbar ) ) + { + self.proxbar hideelem(); + } + if ( isDefined( self.proxbartext ) ) + { + self.proxbartext hideelem(); + } + return; + } + else if ( !isDefined( self.proxbar ) ) + { + self.proxbar = createprimaryprogressbar(); + self.proxbar.lastuserate = -1; + } + if ( self.pers[ "team" ] == object.claimteam ) + { + if ( self.proxbar.bar.color != ( 0, 0, 1 ) ) + { + self.proxbar.bar.color = ( 0, 0, 1 ); + self.proxbar.lastuserate = -1; + } + } + else + { + if ( self.proxbar.bar.color != ( 0, 0, 1 ) ) + { + self.proxbar.bar.color = ( 0, 0, 1 ); + self.proxbar.lastuserate = -1; + } + } + } + else + { + if ( !forceremove || !object caninteractwith( self ) && self.pers[ "team" ] != object.claimteam ) + { + if ( isDefined( self.proxbar ) ) + { + self.proxbar hideelem(); + } + if ( isDefined( self.proxbartext ) ) + { + self.proxbartext hideelem(); + } + return; + } + } + if ( !isDefined( self.proxbar ) ) + { + self.proxbar = self createprimaryprogressbar(); + self.proxbar.lastuserate = -1; + self.proxbar.lasthostmigrationstate = 0; + } + if ( self.proxbar.hidden ) + { + self.proxbar showelem(); + self.proxbar.lastuserate = -1; + self.proxbar.lasthostmigrationstate = 0; + } + if ( !isDefined( self.proxbartext ) ) + { + self.proxbartext = self createprimaryprogressbartext(); + self.proxbartext settext( object.usetext ); + } + if ( self.proxbartext.hidden ) + { + self.proxbartext showelem(); + self.proxbartext settext( object.usetext ); + } + if ( self.proxbar.lastuserate != object.userate || self.proxbar.lasthostmigrationstate != isDefined( level.hostmigrationtimer ) ) + { + if ( object.curprogress > object.usetime ) + { + object.curprogress = object.usetime; + } + if ( object.decayprogress && self.pers[ "team" ] != object.claimteam ) + { + if ( object.curprogress > 0 ) + { + progress = object.curprogress / object.usetime; + rate = ( 1000 / object.usetime ) * ( object.userate * -1 ); + if ( isDefined( level.hostmigrationtimer ) ) + { + rate = 0; + } + self.proxbar updatebar( progress, rate ); + } + } + else + { + progress = object.curprogress / object.usetime; + rate = ( 1000 / object.usetime ) * object.userate; + if ( isDefined( level.hostmigrationtimer ) ) + { + rate = 0; + } + self.proxbar updatebar( progress, rate ); + } + self.proxbar.lasthostmigrationstate = isDefined( level.hostmigrationtimer ); + self.proxbar.lastuserate = object.userate; + } +} + +getnumtouchingexceptteam( ignoreteam ) +{ + numtouching = 0; + _a1902 = level.teams; + _k1902 = getFirstArrayKey( _a1902 ); + while ( isDefined( _k1902 ) ) + { + team = _a1902[ _k1902 ]; + if ( ignoreteam == team ) + { + } + else + { + numtouching += self.numtouching[ team ]; + } + _k1902 = getNextArrayKey( _a1902, _k1902 ); + } + return numtouching; +} + +updateuserate() +{ + numclaimants = self.numtouching[ self.claimteam ]; + numother = 0; + numother = getnumtouchingexceptteam( self.claimteam ); + self.userate = 0; + if ( self.decayprogress ) + { + if ( numclaimants && !numother ) + { + self.userate = numclaimants; + } + else + { + if ( !numclaimants && numother ) + { + self.userate = numother; + } + else + { + if ( !numclaimants && !numother ) + { + self.userate = 0; + } + } + } + } + else + { + if ( numclaimants && !numother ) + { + self.userate = numclaimants; + } + } + if ( isDefined( self.onupdateuserate ) ) + { + self [[ self.onupdateuserate ]](); + } +} + +useholdthink( player ) +{ + player notify( "use_hold" ); + if ( isDefined( self.dontlinkplayertotrigger ) && !self.dontlinkplayertotrigger ) + { + player playerlinkto( self.trigger ); + player playerlinkedoffsetenable(); + } + player clientclaimtrigger( self.trigger ); + player.claimtrigger = self.trigger; + useweapon = self.useweapon; + lastweapon = player getcurrentweapon(); + if ( isDefined( useweapon ) ) + { +/# + assert( isDefined( lastweapon ) ); +#/ + if ( lastweapon == useweapon ) + { +/# + assert( isDefined( player.lastnonuseweapon ) ); +#/ + lastweapon = player.lastnonuseweapon; + } +/# + assert( lastweapon != useweapon ); +#/ + player.lastnonuseweapon = lastweapon; + player giveweapon( useweapon ); + player setweaponammostock( useweapon, 0 ); + player setweaponammoclip( useweapon, 0 ); + player switchtoweapon( useweapon ); + } + else + { + player _disableweapon(); + } + self clearprogress(); + self.inuse = 1; + self.userate = 0; + objective_setplayerusing( self.objectiveid, player ); + player thread personalusebar( self ); + result = useholdthinkloop( player, lastweapon ); + if ( isDefined( player ) ) + { + objective_clearplayerusing( self.objectiveid, player ); + self clearprogress(); + if ( isDefined( player.attachedusemodel ) ) + { + player detach( player.attachedusemodel, "tag_inhand" ); + player.attachedusemodel = undefined; + } + player notify( "done_using" ); + } + if ( isDefined( useweapon ) && isDefined( player ) ) + { + player thread takeuseweapon( useweapon ); + } + if ( isDefined( result ) && result ) + { + return 1; + } + if ( isDefined( player ) ) + { + player.claimtrigger = undefined; + if ( isDefined( useweapon ) ) + { + ammo = player getweaponammoclip( lastweapon ); + if ( lastweapon != "none" && isweaponequipment( lastweapon ) && player getweaponammoclip( lastweapon ) != 0 ) + { + player switchtoweapon( lastweapon ); + } + else + { + player takeweapon( useweapon ); + } + } + else + { + if ( isalive( player ) ) + { + player _enableweapon(); + } + } + if ( isDefined( self.dontlinkplayertotrigger ) && !self.dontlinkplayertotrigger ) + { + player unlink(); + } + if ( !isalive( player ) ) + { + player.killedinuse = 1; + } + } + self.inuse = 0; + if ( self.trigger.classname == "trigger_radius_use" ) + { + player clientreleasetrigger( self.trigger ); + } + else + { + self.trigger releaseclaimedtrigger(); + } + return 0; +} + +takeuseweapon( useweapon ) +{ + self endon( "use_hold" ); + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + while ( self getcurrentweapon() == useweapon && !self.throwinggrenade ) + { + wait 0,05; + } + self takeweapon( useweapon ); +} + +continueholdthinkloop( player, waitforweapon, timedout, usetime ) +{ + maxwaittime = 1,5; + if ( !isalive( player ) ) + { + return 0; + } + if ( isDefined( player.laststand ) && player.laststand ) + { + return 0; + } + if ( self.curprogress >= usetime ) + { + return 0; + } + if ( !player usebuttonpressed() ) + { + return 0; + } + if ( player.throwinggrenade ) + { + return 0; + } + if ( player meleebuttonpressed() ) + { + return 0; + } + if ( player isinvehicle() ) + { + return 0; + } + if ( player isremotecontrolling() ) + { + return 0; + } + if ( player isweaponviewonlylinked() ) + { + return 0; + } + if ( !player istouching( self.trigger ) ) + { + return 0; + } + if ( !self.userate && !waitforweapon ) + { + return 0; + } + if ( waitforweapon && timedout > maxwaittime ) + { + return 0; + } + return 1; +} + +updatecurrentprogress() +{ + if ( self.usetime ) + { + progress = float( self.curprogress ) / self.usetime; + objective_setprogress( self.objectiveid, clamp( progress, 0, 1 ) ); + } +} + +useholdthinkloop( player, lastweapon ) +{ + level endon( "game_ended" ); + self endon( "disabled" ); + useweapon = self.useweapon; + waitforweapon = 1; + timedout = 0; + usetime = self.usetime; + while ( self continueholdthinkloop( player, waitforweapon, timedout, usetime ) ) + { + timedout += 0,05; + if ( !isDefined( useweapon ) || player getcurrentweapon() == useweapon ) + { + self.curprogress += 50 * self.userate; + self updatecurrentprogress(); + self.userate = 1; + waitforweapon = 0; + } + else + { + self.userate = 0; + } + if ( self.curprogress >= usetime ) + { + self.inuse = 0; + player clientreleasetrigger( self.trigger ); + player.claimtrigger = undefined; + if ( isDefined( useweapon ) ) + { + player setweaponammostock( useweapon, 1 ); + player setweaponammoclip( useweapon, 1 ); + if ( lastweapon != "none" && isweaponequipment( lastweapon ) && player getweaponammoclip( lastweapon ) != 0 ) + { + player switchtoweapon( lastweapon ); + } + else + { + player takeweapon( useweapon ); + } + } + else + { + player _enableweapon(); + } + if ( isDefined( self.dontlinkplayertotrigger ) && !self.dontlinkplayertotrigger ) + { + player unlink(); + } + wait 0,05; + return isalive( player ); + } + wait 0,05; + maps/mp/gametypes_zm/_hostmigration::waittillhostmigrationdone(); + } + return 0; +} + +personalusebar( object ) +{ + self endon( "disconnect" ); + if ( object.newstyle ) + { + return; + } + if ( isDefined( self.usebar ) ) + { + return; + } + self.usebar = self createprimaryprogressbar(); + self.usebartext = self createprimaryprogressbartext(); + self.usebartext settext( object.usetext ); + usetime = object.usetime; + lastrate = -1; + lasthostmigrationstate = isDefined( level.hostmigrationtimer ); + while ( isalive( self ) && object.inuse && !level.gameended ) + { + if ( lastrate != object.userate || lasthostmigrationstate != isDefined( level.hostmigrationtimer ) ) + { + if ( object.curprogress > usetime ) + { + object.curprogress = usetime; + } + if ( object.decayprogress && self.pers[ "team" ] != object.claimteam ) + { + if ( object.curprogress > 0 ) + { + progress = object.curprogress / usetime; + rate = ( 1000 / usetime ) * ( object.userate * -1 ); + if ( isDefined( level.hostmigrationtimer ) ) + { + rate = 0; + } + self.proxbar updatebar( progress, rate ); + } + } + else + { + progress = object.curprogress / usetime; + rate = ( 1000 / usetime ) * object.userate; + if ( isDefined( level.hostmigrationtimer ) ) + { + rate = 0; + } + self.usebar updatebar( progress, rate ); + } + if ( !object.userate ) + { + self.usebar hideelem(); + self.usebartext hideelem(); + } + else + { + self.usebar showelem(); + self.usebartext showelem(); + } + } + lastrate = object.userate; + lasthostmigrationstate = isDefined( level.hostmigrationtimer ); + wait 0,05; + } + self.usebar destroyelem(); + self.usebartext destroyelem(); +} + +updatetrigger() +{ + if ( self.triggertype != "use" ) + { + return; + } + if ( self.interactteam == "none" ) + { + self.trigger.origin -= vectorScale( ( 0, 0, 1 ), 50000 ); + } + else if ( self.interactteam == "any" || !level.teambased ) + { + self.trigger.origin = self.curorigin; + self.trigger setteamfortrigger( "none" ); + } + else + { + if ( self.interactteam == "friendly" ) + { + self.trigger.origin = self.curorigin; + if ( isDefined( level.teams[ self.ownerteam ] ) ) + { + self.trigger setteamfortrigger( self.ownerteam ); + } + else + { + self.trigger.origin -= vectorScale( ( 0, 0, 1 ), 50000 ); + } + return; + } + else + { + if ( self.interactteam == "enemy" ) + { + self.trigger.origin = self.curorigin; + self.trigger setexcludeteamfortrigger( self.ownerteam ); + } + } + } +} + +updateobjective() +{ + if ( !self.newstyle ) + { + return; + } + objective_team( self.objectiveid, self.ownerteam ); + if ( self.visibleteam == "any" ) + { + objective_state( self.objectiveid, "active" ); + objective_visibleteams( self.objectiveid, level.spawnsystem.ispawn_teammask[ "all" ] ); + } + else if ( self.visibleteam == "friendly" ) + { + objective_state( self.objectiveid, "active" ); + objective_visibleteams( self.objectiveid, level.spawnsystem.ispawn_teammask[ self.ownerteam ] ); + } + else if ( self.visibleteam == "enemy" ) + { + objective_state( self.objectiveid, "active" ); + objective_visibleteams( self.objectiveid, level.spawnsystem.ispawn_teammask[ "all" ] & level.spawnsystem.ispawn_teammask[ self.ownerteam ] ); + } + else + { + objective_state( self.objectiveid, "invisible" ); + objective_visibleteams( self.objectiveid, 0 ); + } + if ( self.type == "carryObject" ) + { + if ( isalive( self.carrier ) ) + { + objective_onentity( self.objectiveid, self.carrier ); + return; + } + else + { + objective_clearentity( self.objectiveid ); + } + } +} + +updateworldicons() +{ + if ( self.visibleteam == "any" ) + { + updateworldicon( "friendly", 1 ); + updateworldicon( "enemy", 1 ); + } + else if ( self.visibleteam == "friendly" ) + { + updateworldicon( "friendly", 1 ); + updateworldicon( "enemy", 0 ); + } + else if ( self.visibleteam == "enemy" ) + { + updateworldicon( "friendly", 0 ); + updateworldicon( "enemy", 1 ); + } + else + { + updateworldicon( "friendly", 0 ); + updateworldicon( "enemy", 0 ); + } +} + +updateworldicon( relativeteam, showicon ) +{ +} + +updatecompassicons() +{ + if ( self.visibleteam == "any" ) + { + updatecompassicon( "friendly", 1 ); + updatecompassicon( "enemy", 1 ); + } + else if ( self.visibleteam == "friendly" ) + { + updatecompassicon( "friendly", 1 ); + updatecompassicon( "enemy", 0 ); + } + else if ( self.visibleteam == "enemy" ) + { + updatecompassicon( "friendly", 0 ); + updatecompassicon( "enemy", 1 ); + } + else + { + updatecompassicon( "friendly", 0 ); + updatecompassicon( "enemy", 0 ); + } +} + +updatecompassicon( relativeteam, showicon ) +{ + if ( self.newstyle ) + { + return; + } + updateteams = getupdateteams( relativeteam ); + index = 0; + while ( index < updateteams.size ) + { + showiconthisteam = showicon; + if ( !showiconthisteam && shouldshowcompassduetoradar( updateteams[ index ] ) ) + { + showiconthisteam = 1; + } + if ( level.teambased ) + { + objid = self.objid[ updateteams[ index ] ]; + } + else + { + objid = self.objid[ level.nonteambasedteam ]; + } + if ( !isDefined( self.compassicons[ relativeteam ] ) || !showiconthisteam ) + { + objective_state( objid, "invisible" ); + index++; + continue; + } + else + { + objective_icon( objid, self.compassicons[ relativeteam ] ); + objective_state( objid, "active" ); + if ( self.type == "carryObject" ) + { + if ( isalive( self.carrier ) && !shouldpingobject( relativeteam ) ) + { + objective_onentity( objid, self.carrier ); + index++; + continue; + } + else + { + objective_position( objid, self.curorigin ); + } + } + } + index++; + } +} + +shouldpingobject( relativeteam ) +{ + if ( relativeteam == "friendly" && self.objidpingfriendly ) + { + return 1; + } + else + { + if ( relativeteam == "enemy" && self.objidpingenemy ) + { + return 1; + } + } + return 0; +} + +getupdateteams( relativeteam ) +{ + updateteams = []; + if ( level.teambased ) + { + if ( relativeteam == "friendly" ) + { + _a2526 = level.teams; + _k2526 = getFirstArrayKey( _a2526 ); + while ( isDefined( _k2526 ) ) + { + team = _a2526[ _k2526 ]; + if ( self isfriendlyteam( team ) ) + { + updateteams[ updateteams.size ] = team; + } + _k2526 = getNextArrayKey( _a2526, _k2526 ); + } + } + else while ( relativeteam == "enemy" ) + { + _a2534 = level.teams; + _k2534 = getFirstArrayKey( _a2534 ); + while ( isDefined( _k2534 ) ) + { + team = _a2534[ _k2534 ]; + if ( !self isfriendlyteam( team ) ) + { + updateteams[ updateteams.size ] = team; + } + _k2534 = getNextArrayKey( _a2534, _k2534 ); + } + } + } + else if ( relativeteam == "friendly" ) + { + updateteams[ updateteams.size ] = level.nonteambasedteam; + } + else + { + updateteams[ updateteams.size ] = "axis"; + } + return updateteams; +} + +shouldshowcompassduetoradar( team ) +{ + showcompass = 0; + return showcompass; +} + +updatevisibilityaccordingtoradar() +{ + self endon( "death" ); + self endon( "carrier_cleared" ); + while ( 1 ) + { + level waittill( "radar_status_change" ); + self updatecompassicons(); + } +} + +setownerteam( team ) +{ + self.ownerteam = team; + self updatetrigger(); + self updatecompassicons(); + self updateworldicons(); + self updateobjective(); +} + +getownerteam() +{ + return self.ownerteam; +} + +setdecaytime( time ) +{ + self.decaytime = int( time * 1000 ); +} + +setusetime( time ) +{ + self.usetime = int( time * 1000 ); +} + +setusetext( text ) +{ + self.usetext = text; +} + +setusehinttext( text ) +{ + self.trigger sethintstring( text ); +} + +allowcarry( relativeteam ) +{ + self.interactteam = relativeteam; +} + +allowuse( relativeteam ) +{ + self.interactteam = relativeteam; + updatetrigger(); +} + +setvisibleteam( relativeteam ) +{ + self.visibleteam = relativeteam; + if ( !maps/mp/gametypes_zm/_tweakables::gettweakablevalue( "hud", "showobjicons" ) ) + { + self.visibleteam = "none"; + } + updatecompassicons(); + updateworldicons(); + updateobjective(); +} + +setmodelvisibility( visibility ) +{ + if ( visibility ) + { + index = 0; + while ( index < self.visuals.size ) + { + self.visuals[ index ] show(); + if ( self.visuals[ index ].classname == "script_brushmodel" || self.visuals[ index ].classname == "script_model" ) + { + self.visuals[ index ] thread makesolid(); + } + index++; + } + } + else index = 0; + while ( index < self.visuals.size ) + { + self.visuals[ index ] hide(); + if ( self.visuals[ index ].classname == "script_brushmodel" || self.visuals[ index ].classname == "script_model" ) + { + self.visuals[ index ] notify( "changing_solidness" ); + self.visuals[ index ] notsolid(); + } + index++; + } +} + +makesolid() +{ + self endon( "death" ); + self notify( "changing_solidness" ); + self endon( "changing_solidness" ); + while ( 1 ) + { + i = 0; + while ( i < level.players.size ) + { + if ( level.players[ i ] istouching( self ) ) + { + break; + } + else + { + i++; + } + } + if ( i == level.players.size ) + { + self solid(); + return; + } + else + { + wait 0,05; + } + } +} + +setcarriervisible( relativeteam ) +{ + self.carriervisible = relativeteam; +} + +setcanuse( relativeteam ) +{ + self.useteam = relativeteam; +} + +set2dicon( relativeteam, shader ) +{ + self.compassicons[ relativeteam ] = shader; + updatecompassicons(); +} + +set3dicon( relativeteam, shader ) +{ + self.worldicons[ relativeteam ] = shader; + updateworldicons(); +} + +set3duseicon( relativeteam, shader ) +{ + self.worlduseicons[ relativeteam ] = shader; +} + +set3diswaypoint( relativeteam, waypoint ) +{ + self.worldiswaypoint[ relativeteam ] = waypoint; +} + +setcarryicon( shader ) +{ + self.carryicon = shader; +} + +setvisiblecarriermodel( visiblemodel ) +{ + self.visiblecarriermodel = visiblemodel; +} + +getvisiblecarriermodel() +{ + return self.visiblecarriermodel; +} + +destroyobject( deletetrigger, forcehide ) +{ + if ( !isDefined( forcehide ) ) + { + forcehide = 1; + } + self disableobject( forcehide ); + _a2742 = self.visuals; + _k2742 = getFirstArrayKey( _a2742 ); + while ( isDefined( _k2742 ) ) + { + visual = _a2742[ _k2742 ]; + visual hide(); + visual delete(); + _k2742 = getNextArrayKey( _a2742, _k2742 ); + } + self.trigger notify( "destroyed" ); + if ( isDefined( deletetrigger ) && deletetrigger ) + { + self.trigger delete(); + } + else + { + self.trigger triggeron(); + } +} + +disableobject( forcehide ) +{ + self notify( "disabled" ); + while ( self.type == "carryObject" || isDefined( forcehide ) && forcehide ) + { + if ( isDefined( self.carrier ) ) + { + self.carrier takeobject( self ); + } + index = 0; + while ( index < self.visuals.size ) + { + self.visuals[ index ] hide(); + index++; + } + } + self.trigger triggeroff(); + self setvisibleteam( "none" ); +} + +enableobject( forceshow ) +{ + while ( self.type == "carryObject" || isDefined( forceshow ) && forceshow ) + { + index = 0; + while ( index < self.visuals.size ) + { + self.visuals[ index ] show(); + index++; + } + } + self.trigger triggeron(); + self setvisibleteam( "any" ); +} + +getrelativeteam( team ) +{ + if ( self.ownerteam == "any" ) + { + return "friendly"; + } + if ( team == self.ownerteam ) + { + return "friendly"; + } + else + { + if ( team == getenemyteam( self.ownerteam ) ) + { + return "enemy"; + } + else + { + return "neutral"; + } + } +} + +isfriendlyteam( team ) +{ + if ( !level.teambased ) + { + return 1; + } + if ( self.ownerteam == "any" ) + { + return 1; + } + if ( self.ownerteam == team ) + { + return 1; + } + return 0; +} + +caninteractwith( player ) +{ + team = player.pers[ "team" ]; + switch( self.interactteam ) + { + case "none": + return 0; + case "any": + return 1; + case "friendly": + if ( level.teambased ) + { + if ( team == self.ownerteam ) + { + return 1; + } + else + { + return 0; + } + } + else + { + if ( player == self.ownerteam ) + { + return 1; + } + else + { + return 0; + } + } + case "enemy": + if ( level.teambased ) + { + if ( team != self.ownerteam ) + { + return 1; + } + else + { + if ( isDefined( self.decayprogress ) && self.decayprogress && self.curprogress > 0 ) + { + return 1; + } + else + { + return 0; + } + } + } + else + { + if ( player != self.ownerteam ) + { + return 1; + } + else + { + return 0; + } + } + default: +/# + assert( 0, "invalid interactTeam" ); +#/ + return 0; + } +} + +isteam( team ) +{ + if ( team == "neutral" ) + { + return 1; + } + if ( isDefined( level.teams[ team ] ) ) + { + return 1; + } + if ( team == "any" ) + { + return 1; + } + if ( team == "none" ) + { + return 1; + } + return 0; +} + +isrelativeteam( relativeteam ) +{ + if ( relativeteam == "friendly" ) + { + return 1; + } + if ( relativeteam == "enemy" ) + { + return 1; + } + if ( relativeteam == "any" ) + { + return 1; + } + if ( relativeteam == "none" ) + { + return 1; + } + return 0; +} + +getenemyteam( team ) +{ + if ( team == "neutral" ) + { + return "none"; + } + else + { + if ( team == "allies" ) + { + return "axis"; + } + else + { + return "allies"; + } + } +} + +getnextobjid() +{ + nextid = 0; + if ( level.releasedobjectives.size > 0 ) + { + nextid = level.releasedobjectives[ level.releasedobjectives.size - 1 ]; + } + else + { + nextid = level.numgametypereservedobjectives; + level.numgametypereservedobjectives++; + } +/# + assert( nextid < 32, "Ran out of objective IDs" ); +#/ + return nextid; +} + +releaseobjid( objid ) +{ +/# + assert( objid < level.numgametypereservedobjectives ); +#/ + i = 0; + while ( i < level.releasedobjectives.size ) + { + if ( objid == level.releasedobjectives[ i ] && objid == 31 ) + { + return; + } +/# + assert( objid != level.releasedobjectives[ i ] ); +#/ + i++; + } + level.releasedobjectives[ level.releasedobjectives.size ] = objid; +} + +getlabel() +{ + label = self.trigger.script_label; + if ( !isDefined( label ) ) + { + label = ""; + return label; + } + if ( label[ 0 ] != "_" ) + { + return "_" + label; + } + return label; +} + +mustmaintainclaim( enabled ) +{ + self.mustmaintainclaim = enabled; +} + +cancontestclaim( enabled ) +{ + self.cancontestclaim = enabled; +} + +setflags( flags ) +{ + objective_setgamemodeflags( self.objectiveid, flags ); +} + +getflags( flags ) +{ + return objective_getgamemodeflags( self.objectiveid ); +} diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic.gsc new file mode 100644 index 0000000..7f3452b --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic.gsc @@ -0,0 +1,3101 @@ +#include maps/mp/gametypes/_globallogic; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/gametypes/_dev; +#include maps/mp/_multi_extracam; +#include maps/mp/gametypes/_friendicons; +#include maps/mp/_bb; +#include maps/mp/gametypes/_battlechatter_mp; +#include maps/mp/gametypes/_healthoverlay; +#include maps/mp/gametypes/_damagefeedback; +#include maps/mp/teams/_teams; +#include maps/mp/gametypes/_menus; +#include maps/mp/_decoy; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_gameobjects; +#include maps/mp/gametypes/_objpoints; +#include maps/mp/gametypes/_spectating; +#include maps/mp/gametypes/_deathicons; +#include maps/mp/gametypes/_shellshock; +#include maps/mp/gametypes/_killcam; +#include maps/mp/gametypes/_scoreboard; +#include maps/mp/gametypes/_weaponobjects; +#include maps/mp/gametypes/_clientids; +#include maps/mp/gametypes/_serversettings; +#include maps/mp/_challenges; +#include maps/mp/_music; +#include maps/mp/gametypes/_weapons; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/_demo; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_wager; +#include maps/mp/gametypes/_persistence; +#include maps/mp/gametypes/_hud; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/bots/_bot; +#include maps/mp/gametypes/_hud_message; +#include maps/mp/gametypes/_globallogic_defaults; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_globallogic_spawn; +#include maps/mp/_gamerep; +#include maps/mp/_gameadvertisement; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_class; +#include maps/mp/gametypes/_globallogic_ui; +#include maps/mp/gametypes/_tweakables; +#include common_scripts/utility; +#include maps/mp/_busing; +#include maps/mp/_burnplayer; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + + +init() +{ + if (!isDefined(level.tweakablesinitialized)) + { + maps/mp/gametypes/_tweakables::init(); + } + init_session_mode_flags(); + level.splitscreen = issplitscreen(); + level.xenon = getDvar(#"0xe0dde627") == "true"; + level.ps3 = getDvar(#"0xc15079f5") == "true"; + level.wiiu = getDvar(#"0xde5d2cdd") == "true"; + level.onlinegame = sessionmodeisonlinegame(); + level.systemlink = sessionmodeissystemlink(); + level.console = level.wiiu; + level.rankedmatch = !(ispregame()); + level.leaguematch = gamemodeismode(level.gamemode_league_match); + level.contractsenabled = !(getgametypesetting("disableContracts")); + level.contractsenabled = 0; + level.script = tolower(getDvar(#"0xb4b895c4")); + level.gametype = tolower(getDvar(#"0x4f118387")); + level.teambased = 0; + level.teamcount = getgametypesetting("teamCount"); + level.multiteam = level.teamcount > 2; + while (sessionmodeiszombiesgame()) + { + level.zombie_team_index = level.teamcount + 1; + if (2 == level.zombie_team_index) + { + level.zombie_team = "axis"; + } + else + { + level.zombie_team = "team" + level.zombie_team_index; + } + } + level.teams = []; + level.teamindex = []; + teamcount = level.teamcount; + level.teams["allies"] = "allies"; + level.teams["axis"] = "axis"; + level.teamindex["neutral"] = 0; + level.teamindex["allies"] = 1; + level.teamindex["axis"] = 2; + teamindex = 3; + while (teamindex <= teamcount) + { + level.teams["team" + teamindex] = "team" + teamindex; + level.teamindex["team" + teamindex] = teamindex; + teamindex++; + } + level.overrideteamscore = 0; + level.overrideplayerscore = 0; + level.displayhalftimetext = 0; + level.displayroundendtext = 1; + level.endgameonscorelimit = 1; + level.endgameontimelimit = 1; + level.scoreroundbased = 0; + level.resetplayerscoreeveryround = 0; + level.gameforfeited = 0; + level.forceautoassign = 0; + level.halftimetype = "halftime"; + level.halftimesubcaption = &"MP_SWITCHING_SIDES_CAPS"; + level.laststatustime = 0; + level.waswinning = []; + level.lastslowprocessframe = 0; + level.placement = []; + _a106 = level.teams; + _k106 = getFirstArrayKey(_a106); + while (isDefined(_k106)) + { + team = _a106[_k106]; + level.placement[team] = []; + _k106 = getNextArrayKey(_a106, _k106); + } + level.placement["all"] = []; + level.postroundtime = 7; + level.inovertime = 0; + level.defaultoffenseradius = 560; + level.dropteam = getDvarInt(#"0x851b42e5"); + level.infinalkillcam = 0; + maps/mp/gametypes/_globallogic_ui::init(); + registerdvars(); + maps/mp/gametypes/_class::initperkdvars(); + level.oldschool = getDvarInt(#"0x38f47b13") == 1; + if (level.oldschool) + { + logstring("game mode: oldschool"); + setdvar("jump_height", 64); + setdvar("jump_slowdownEnable", 0); + setdvar("bg_fallDamageMinHeight", 256); + setdvar("bg_fallDamageMaxHeight", 512); + setdvar("player_clipSizeMultiplier", 2); + } + precachemodel("tag_origin"); + precacherumble("dtp_rumble"); + precacherumble("slide_rumble"); + precachestatusicon("hud_status_dead"); + precachestatusicon("hud_status_connecting"); + precache_mp_leaderboards(); + maps/mp/_burnplayer::initburnplayer(); + if (!isDefined(game["tiebreaker"])) + { + game["tiebreaker"] = 0; + } + maps/mp/gametypes/_globallogic_audio::registerdialoggroup("introboost", 1); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup("status", 1); + thread maps/mp/_gameadvertisement::init(); + thread maps/mp/_gamerep::init(); + level.disablechallenges = 0; + while (level.leaguematch || getDvarInt(#"0x8d5c0c16") > 0) + { + level.disablechallenges = 1; + } + level.disablestattracking = getDvarInt(#"0x742cbfaf") > 0; +} + +registerdvars() +{ + if (getDvar(#"0x38f47b13") == "") + { + setdvar("scr_oldschool", "0"); + } + makedvarserverinfo("scr_oldschool"); + if (getDvar(#"0x6017b9c") == "") + { + setdvar("ui_guncycle", 0); + } + makedvarserverinfo("ui_guncycle"); + if (getDvar(#"0x41a6c572") == "") + { + setdvar("ui_weapon_tiers", 0); + } + makedvarserverinfo("ui_weapon_tiers"); + setdvar("ui_text_endreason", ""); + makedvarserverinfo("ui_text_endreason", ""); + setmatchflag("bomb_timer", 0); + setmatchflag("enable_popups", 1); + setmatchflag("pregame", ispregame()); + if (getDvar(#"0x23853f1f") == "") + { + setdvar("scr_vehicle_damage_scalar", "1"); + } + level.vehicledamagescalar = getDvarFloat(#"0x23853f1f"); + level.fire_audio_repeat_duration = getDvarInt(#"0x917e4521"); + level.fire_audio_random_max_duration = getDvarInt(#"0xc2dcbc26"); + teamname = getcustomteamname(level.teamindex["allies"]); + if (isDefined(teamname)) + { + setdvar("g_customTeamName_Allies", teamname); + } + else + { + setdvar("g_customTeamName_Allies", ""); + } + teamname = getcustomteamname(level.teamindex["axis"]); + if (isDefined(teamname)) + { + setdvar("g_customTeamName_Axis", teamname); + } + else + { + setdvar("g_customTeamName_Axis", ""); + } +} + +blank(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) +{ +} + +setupcallbacks() +{ + level.spawnplayer = ::spawnplayer; + level.spawnplayerprediction = ::spawnplayerprediction; + level.spawnclient = ::spawnclient; + level.spawnspectator = ::spawnspectator; + level.spawnintermission = ::spawnintermission; + level.onplayerscore = ::default_onplayerscore; + level.onteamscore = ::default_onteamscore; + level.wavespawntimer = ::wavespawntimer; + level.spawnmessage = ::default_spawnmessage; + level.onspawnplayer = ::blank; + level.onspawnplayerunified = ::blank; + level.onspawnspectator = ::default_onspawnspectator; + level.onspawnintermission = ::default_onspawnintermission; + level.onrespawndelay = ::blank; + level.onforfeit = ::default_onforfeit; + level.ontimelimit = ::default_ontimelimit; + level.onscorelimit = ::default_onscorelimit; + level.onalivecountchange = ::default_onalivecountchange; + level.ondeadevent = undefined; + level.ononeleftevent = ::default_ononeleftevent; + level.giveteamscore = ::giveteamscore; + level.onlastteamaliveevent = ::default_onlastteamaliveevent; + level.gettimelimit = ::default_gettimelimit; + level.getteamkillpenalty = ::default_getteamkillpenalty; + level.getteamkillscore = ::default_getteamkillscore; + level.iskillboosting = ::default_iskillboosting; + level._setteamscore = ::_setteamscore; + level._setplayerscore = ::_setplayerscore; + level._getteamscore = ::_getteamscore; + level._getplayerscore = ::_getplayerscore; + level.onprecachegametype = ::blank; + level.onstartgametype = ::blank; + level.onplayerconnect = ::blank; + level.onplayerdisconnect = ::blank; + level.onplayerdamage = ::blank; + level.onplayerkilled = ::blank; + level.onplayerkilledextraunthreadedcbs = []; + level.onteamoutcomenotify = ::teamoutcomenotify; + level.onoutcomenotify = ::outcomenotify; + level.onteamwageroutcomenotify = ::teamwageroutcomenotify; + level.onwageroutcomenotify = ::wageroutcomenotify; + level.setmatchscorehudelemforteam = ::setmatchscorehudelemforteam; + level.onendgame = ::blank; + level.onroundendgame = ::default_onroundendgame; + level.onmedalawarded = ::blank; + maps/mp/gametypes/_globallogic_ui::setupcallbacks(); +} + +precache_mp_leaderboards() +{ + if (maps/mp/bots/_bot::is_bot_ranked_match()) + { + return; + } + if (sessionmodeiszombiesgame()) + { + return; + } + if (!level.rankedmatch) + { + return; + } + mapname = getDvar(#"0xb4b895c4"); + globalleaderboards = "LB_MP_GB_XPPRESTIGE LB_MP_GB_SCORE LB_MP_GB_KDRATIO LB_MP_GB_KILLS LB_MP_GB_WINS LB_MP_GB_DEATHS LB_MP_GB_XPMAXPERGAME LB_MP_GB_TACTICALINSERTS LB_MP_GB_TACTICALINSERTSKILLS LB_MP_GB_PRESTIGEXP LB_MP_GB_HEADSHOTS LB_MP_GB_WEAPONS_PRIMARY LB_MP_GB_WEAPONS_SECONDARY"; + careerleaderboard = ""; + switch (level.gametype) + { + case "gun": + case "oic": + case "sas": + case "shrp": + break; + + default: + careerleaderboard = " LB_MP_GB_SCOREPERMINUTE"; + break; + + } + gamemodeleaderboard = " LB_MP_GM_" + level.gametype; + gamemodeleaderboardext = " LB_MP_GM_" + level.gametype + "_EXT"; + gamemodehcleaderboard = ""; + gamemodehcleaderboardext = ""; + hardcoremode = getgametypesetting("hardcoreMode"); + if (isDefined(hardcoremode) && hardcoremode) + { + gamemodehcleaderboard = gamemodeleaderboard + "_HC"; + gamemodehcleaderboardext = gamemodeleaderboardext + "_HC"; + } + mapleaderboard = " LB_MP_MAP_" + getsubstr(mapname, 3, mapname.size); + precacheleaderboards(globalleaderboards + careerleaderboard + gamemodeleaderboard + gamemodeleaderboardext + gamemodehcleaderboard + gamemodehcleaderboardext + mapleaderboard); +} + +compareteambygamestat(gamestat, teama, teamb, previous_winner_score) +{ + winner = undefined; + if (teama == "tie") + { + winner = "tie"; + if (previous_winner_score < game[gamestat][teamb]) + { + winner = teamb; + } + } + else + { + if (game[gamestat][teama] == game[gamestat][teamb]) + { + winner = "tie"; + } + else + { + if (game[gamestat][teamb] > game[gamestat][teama]) + { + winner = teamb; + } + else + { + winner = teama; + } + } + } + return winner; +} + +determineteamwinnerbygamestat(gamestat) +{ + teamkeys = getarraykeys(level.teams); + winner = teamkeys[0]; + previous_winner_score = game[gamestat][winner]; + teamindex = 1; + while (teamindex < teamkeys.size) + { + winner = compareteambygamestat(gamestat, winner, teamkeys[teamindex], previous_winner_score); + if (winner != "tie") + { + previous_winner_score = game[gamestat][winner]; + } + teamindex++; + } + return winner; +} + +compareteambyteamscore(teama, teamb, previous_winner_score) +{ + winner = undefined; + teambscore = [[level._getteamscore]](teamb); + if (teama == "tie") + { + winner = "tie"; + if (previous_winner_score < teambscore) + { + winner = teamb; + } + return winner; + } + teamascore = [[level._getteamscore]](teama); + if (teambscore == teamascore) + { + winner = "tie"; + } + else + { + if (teambscore > teamascore) + { + winner = teamb; + } + else + { + winner = teama; + } + } + return winner; +} + +determineteamwinnerbyteamscore() +{ + teamkeys = getarraykeys(level.teams); + winner = teamkeys[0]; + previous_winner_score = [[level._getteamscore]](winner); + teamindex = 1; + while (teamindex < teamkeys.size) + { + winner = compareteambyteamscore(winner, teamkeys[teamindex], previous_winner_score); + if (winner != "tie") + { + previous_winner_score = [[level._getteamscore]](winner); + } + teamindex++; + } + return winner; +} + +forceend(hostsucks) +{ + if (!isDefined(hostsucks)) + { + hostsucks = 0; + } + if (level.hostforcedend || level.forcedend) + { + return; + } + winner = undefined; + if (level.teambased) + { + winner = determineteamwinnerbygamestat("teamScores"); + maps/mp/gametypes/_globallogic_utils::logteamwinstring("host ended game", winner); + } + else + { + winner = maps/mp/gametypes/_globallogic_score::gethighestscoringplayer(); + if (isDefined(winner)) + { + logstring("host ended game, win: " + winner.name); + } + else + { + logstring("host ended game, tie"); + } + } + level.forcedend = 1; + level.hostforcedend = 1; + if (hostsucks) + { + endstring = &"MP_HOST_SUCKS"; + } + else + { + if (level.splitscreen) + { + endstring = &"MP_ENDED_GAME"; + } + else + { + endstring = &"MP_HOST_ENDED_GAME"; + } + } + setmatchflag("disableIngameMenu", 1); + makedvarserverinfo("ui_text_endreason", endstring); + setdvar("ui_text_endreason", endstring); + thread endgame(winner, endstring); +} + +killserverpc() +{ + if (level.hostforcedend || level.forcedend) + { + return; + } + winner = undefined; + if (level.teambased) + { + winner = determineteamwinnerbygamestat("teamScores"); + maps/mp/gametypes/_globallogic_utils::logteamwinstring("host ended game", winner); + } + else + { + winner = maps/mp/gametypes/_globallogic_score::gethighestscoringplayer(); + if (isDefined(winner)) + { + logstring("host ended game, win: " + winner.name); + } + else + { + logstring("host ended game, tie"); + } + } + level.forcedend = 1; + level.hostforcedend = 1; + level.killserver = 1; + endstring = &"MP_HOST_ENDED_GAME"; + thread endgame(winner, endstring); +} + +atleasttwoteams() +{ + valid_count = 0; + _a504 = level.teams; + _k504 = getFirstArrayKey(_a504); + while (isDefined(_k504)) + { + team = _a504[_k504]; + if (level.playercount[team] != 0) + { + valid_count++; + } + _k504 = getNextArrayKey(_a504, _k504); + } + if (valid_count < 2) + { + return 0; + } + return 1; +} + +checkifteamforfeits(team) +{ + if (!game["everExisted"][team]) + { + return 0; + } + if (level.playercount[team] < 1 && totalplayercount() > 0) + { + return 1; + } + return 0; +} + +checkforforfeit() +{ + forfeit_count = 0; + valid_team = undefined; + _a538 = level.teams; + _k538 = getFirstArrayKey(_a538); + while (isDefined(_k538)) + { + team = _a538[_k538]; + if (checkifteamforfeits(team)) + { + forfeit_count++; + if (!level.multiteam) + { + thread [[level.onforfeit]](team); + return 1; + } + } + else + { + valid_team = team; + } + _k538 = getNextArrayKey(_a538, _k538); + } + if (level.multiteam && forfeit_count == level.teams.size - 1) + { + thread [[level.onforfeit]](valid_team); + return 1; + } + return 0; +} + +dospawnqueueupdates() +{ + _a567 = level.teams; + _k567 = getFirstArrayKey(_a567); + while (isDefined(_k567)) + { + team = _a567[_k567]; + if (level.spawnqueuemodified[team]) + { + [[level.onalivecountchange]](team); + } + _k567 = getNextArrayKey(_a567, _k567); + } +} + +isteamalldead(team) +{ + return !(level.playerlives[team]); +} + +areallteamsdead() +{ + _a583 = level.teams; + _k583 = getFirstArrayKey(_a583); + while (isDefined(_k583)) + { + team = _a583[_k583]; + if (!isteamalldead(team)) + { + return 0; + } + _k583 = getNextArrayKey(_a583, _k583); + } + return 1; +} + +getlastteamalive() +{ + count = 0; + everexistedcount = 0; + aliveteam = undefined; + _a600 = level.teams; + _k600 = getFirstArrayKey(_a600); + while (isDefined(_k600)) + { + team = _a600[_k600]; + if (level.everexisted[team]) + { + if (!isteamalldead(team)) + { + aliveteam = team; + count++; + } + everexistedcount++; + } + _k600 = getNextArrayKey(_a600, _k600); + } + if (everexistedcount > 1 && count == 1) + { + return aliveteam; + } + return undefined; +} + +dodeadeventupdates() +{ + if (level.teambased) + { + if (areallteamsdead()) + { + [[level.ondeadevent]]("all"); + return 1; + } + if (!isDefined(level.ondeadevent)) + { + lastteamalive = getlastteamalive(); + if (isDefined(lastteamalive)) + { + [[level.onlastteamaliveevent]](lastteamalive); + return 1; + } + } + else + { + _a644 = level.teams; + _k644 = getFirstArrayKey(_a644); + while (isDefined(_k644)) + { + team = _a644[_k644]; + if (isteamalldead(team)) + { + [[level.ondeadevent]](team); + return 1; + } + _k644 = getNextArrayKey(_a644, _k644); + } + } + } + else + { + if (totalalivecount() == 0 && totalplayerlives() == 0 && level.maxplayercount > 1) + { + [[level.ondeadevent]]("all"); + return 1; + } + } + return 0; +} + +isonlyoneleftaliveonteam(team) +{ + return level.playerlives[team] == 1; +} + +doonelefteventupdates() +{ + if (level.teambased) + { + _a678 = level.teams; + _k678 = getFirstArrayKey(_a678); + while (isDefined(_k678)) + { + team = _a678[_k678]; + if (isonlyoneleftaliveonteam(team)) + { + [[level.ononeleftevent]](team); + return 1; + } + _k678 = getNextArrayKey(_a678, _k678); + } + } + else + { + if (totalalivecount() == 1 && totalplayerlives() == 1 && level.maxplayercount > 1) + { + [[level.ononeleftevent]]("all"); + return 1; + } + } + return 0; +} + +updategameevents() +{ + if (level.rankedmatch || level.wagermatch || level.leaguematch && !(level.ingraceperiod)) + { + if (level.teambased) + { + if (!level.gameforfeited) + { + if (game["state"] == "playing" && checkforforfeit()) + { + return; + } + } + else + { + if (atleasttwoteams()) + { + level.gameforfeited = 0; + level notify("abort forfeit"); + } + } + } + else + { + if (!level.gameforfeited) + { + if (totalplayercount() == 1 && level.maxplayercount > 1) + { + thread [[level.onforfeit]](); + return; + } + } + else + { + if (totalplayercount() > 1) + { + level.gameforfeited = 0; + level notify("abort forfeit"); + } + } + } + } + if (!(level.playerqueuedrespawn) && !(level.numlives) && !(level.inovertime)) + { + return; + } + if (level.ingraceperiod) + { + return; + } + while (level.playerqueuedrespawn) + { + dospawnqueueupdates(); + } + if (dodeadeventupdates()) + { + return; + } + if (doonelefteventupdates()) + { + return; + } +} + +matchstarttimer() +{ + visionsetnaked("mpIntro", 0); + matchstarttext = createserverfontstring("objective", 1,5); + matchstarttext setpoint("CENTER", "CENTER", 0, -40); + matchstarttext.sort = 1001; + matchstarttext settext(game["strings"]["waiting_for_teams"]); + matchstarttext.foreground = 0; + matchstarttext.hidewheninmenu = 1; + waitforplayers(); + matchstarttext settext(game["strings"]["match_starting_in"]); + matchstarttimer = createserverfontstring("big", 2,2); + matchstarttimer setpoint("CENTER", "CENTER", 0, 0); + matchstarttimer.sort = 1001; + matchstarttimer.color = (1, 1, 0); + matchstarttimer.foreground = 0; + matchstarttimer.hidewheninmenu = 1; + matchstarttimer maps/mp/gametypes/_hud::fontpulseinit(); + counttime = int(level.prematchperiod); + if (counttime >= 2) + { + while (counttime > 0 && !(level.gameended)) + { + matchstarttimer setvalue(counttime); + matchstarttimer thread maps/mp/gametypes/_hud::fontpulse(level); + if (counttime == 2) + { + visionsetnaked(getDvar(#"0xb4b895c4"), 3); + } + counttime--; + _a804 = level.players; + _k804 = getFirstArrayKey(_a804); + while (isDefined(_k804)) + { + player = _a804[_k804]; + player playlocalsound("uin_start_count_down"); + _k804 = getNextArrayKey(_a804, _k804); + } + wait 1; + } + } + else + { + visionsetnaked(getDvar(#"0xb4b895c4"), 1); + } + matchstarttimer destroyelem(); + matchstarttext destroyelem(); +} + +matchstarttimerskip() +{ + if (!ispregame()) + { + visionsetnaked(getDvar(#"0xb4b895c4"), 0); + } + else + { + visionsetnaked("mpIntro", 0); + } +} + +notifyteamwavespawn(team, time) +{ + if (time - level.lastwave[team] > level.wavedelay[team] * 1000) + { + level notify("wave_respawn_" + team); + level.lastwave[team] = time; + level.waveplayerspawnindex[team] = 0; + } +} + +wavespawntimer() +{ + level endon("game_ended"); + while (game["state"] == "playing") + { + time = getTime(); + _a847 = level.teams; + _k847 = getFirstArrayKey(_a847); + while (isDefined(_k847)) + { + team = _a847[_k847]; + notifyteamwavespawn(team, time); + _k847 = getNextArrayKey(_a847, _k847); + } + wait 0.05; + } +} + +hostidledout() +{ + hostplayer = gethostplayer(); + if (isDefined(hostplayer) && !(hostplayer.hasspawned) && !(isDefined(hostplayer.selectedclass))) + { + return 1; + } + return 0; +} + +incrementmatchcompletionstat(gamemode, playedorhosted, stat) +{ + self adddstat("gameHistory", gamemode, "modeHistory", playedorhosted, stat, 1); +} + +setmatchcompletionstat(gamemode, playedorhosted, stat) +{ + self setdstat("gameHistory", gamemode, "modeHistory", playedorhosted, stat, 1); +} + +getcurrentgamemode() +{ + while (gamemodeismode(level.gamemode_league_match)) + { + return "leaguematch"; + } + return "publicmatch"; +} + +getteamscoreratio() +{ + playerteam = self.pers["team"]; + score = getteamscore(playerteam); + otherteamscore = 0; + _a898 = level.teams; + _k898 = getFirstArrayKey(_a898); + while (isDefined(_k898)) + { + team = _a898[_k898]; + if (team == playerteam) + { + } + else + { + otherteamscore = otherteamscore + getteamscore(team); + } + _k898 = getNextArrayKey(_a898, _k898); + } + if (level.teams.size > 1) + { + otherteamscore = otherteamscore / level.teams.size - 1; + } + if (otherteamscore != 0) + { + return float(score) / float(otherteamscore); + } + return score; +} + +gethighestscore() +{ + highestscore = -999999999; + index = 0; + while (index < level.players.size) + { + player = level.players[index]; + if (player.score > highestscore) + { + highestscore = player.score; + } + index++; + } + return highestscore; +} + +getnexthighestscore(score) +{ + highestscore = -999999999; + index = 0; + while (index < level.players.size) + { + player = level.players[index]; + if (player.score >= score) + { + } + else + { + if (player.score > highestscore) + { + highestscore = player.score; + } + } + index++; + } + return highestscore; +} + +sendafteractionreport() +{ + if (!level.onlinegame) + { + return; + } + if (ispregame()) + { + return; + } + if (sessionmodeiszombiesgame()) + { + return; + } + index = 0; + while (index < level.players.size) + { + player = level.players[index]; + if (player is_bot()) + { + } + else + { + nemesis = player.pers["nemesis_name"]; + if (!isDefined(player.pers["killed_players"][nemesis])) + { + player.pers["killed_players"][nemesis] = 0; + } + if (!isDefined(player.pers["killed_by"][nemesis])) + { + player.pers["killed_by"][nemesis] = 0; + } + spread = player.kills - player.deaths; + if (player.pers["cur_kill_streak"] > player.pers["best_kill_streak"]) + { + player.pers["best_kill_streak"] = player.pers["cur_kill_streak"]; + } + if (level.rankedmatch || level.wagermatch || level.leaguematch) + { + player maps/mp/gametypes/_persistence::setafteractionreportstat("privateMatch", 0); + } + else + { + player maps/mp/gametypes/_persistence::setafteractionreportstat("privateMatch", 1); + } + player setnemesisxuid(player.pers["nemesis_xuid"]); + player maps/mp/gametypes/_persistence::setafteractionreportstat("nemesisName", nemesis); + player maps/mp/gametypes/_persistence::setafteractionreportstat("nemesisRank", player.pers["nemesis_rank"]); + player maps/mp/gametypes/_persistence::setafteractionreportstat("nemesisRankIcon", player.pers["nemesis_rankIcon"]); + player maps/mp/gametypes/_persistence::setafteractionreportstat("nemesisKills", player.pers["killed_players"][nemesis]); + player maps/mp/gametypes/_persistence::setafteractionreportstat("nemesisKilledBy", player.pers["killed_by"][nemesis]); + player maps/mp/gametypes/_persistence::setafteractionreportstat("bestKillstreak", player.pers["best_kill_streak"]); + player maps/mp/gametypes/_persistence::setafteractionreportstat("kills", player.kills); + player maps/mp/gametypes/_persistence::setafteractionreportstat("deaths", player.deaths); + player maps/mp/gametypes/_persistence::setafteractionreportstat("headshots", player.headshots); + player maps/mp/gametypes/_persistence::setafteractionreportstat("score", player.score); + player maps/mp/gametypes/_persistence::setafteractionreportstat("xpEarned", int(player.pers["summary"]["xp"])); + player maps/mp/gametypes/_persistence::setafteractionreportstat("cpEarned", int(player.pers["summary"]["codpoints"])); + player maps/mp/gametypes/_persistence::setafteractionreportstat("miscBonus", int(player.pers["summary"]["challenge"] + player.pers["summary"]["misc"])); + player maps/mp/gametypes/_persistence::setafteractionreportstat("matchBonus", int(player.pers["summary"]["match"])); + player maps/mp/gametypes/_persistence::setafteractionreportstat("demoFileID", getdemofileid()); + player maps/mp/gametypes/_persistence::setafteractionreportstat("leagueTeamID", player getleagueteamid()); + teamscoreratio = player getteamscoreratio(); + scoreboardposition = getplacementforplayer(player); + if (scoreboardposition < 0) + { + scoreboardposition = level.players.size; + } + player gamehistoryfinishmatch(4, player.kills, player.deaths, player.score, scoreboardposition, teamscoreratio); + placement = level.placement["all"]; + otherplayerindex = 0; + while (otherplayerindex < placement.size) + { + while (level.placement["all"][otherplayerindex] == player) + { + recordplayerstats(player, "position", otherplayerindex); + } + otherplayerindex++; + } + if (level.wagermatch) + { + recordplayerstats(player, "wagerPayout", player.wagerwinnings); + player maps/mp/gametypes/_wager::setwagerafteractionreportstats(); + player maps/mp/gametypes/_persistence::setafteractionreportstat("wagerMatch", 1); + } + else + { + player maps/mp/gametypes/_persistence::setafteractionreportstat("wagerMatch", 0); + } + player maps/mp/gametypes/_persistence::setafteractionreportstat("wagerMatchFailed", 0); + if (level.rankedmatch || level.wagermatch || level.leaguematch) + { + player maps/mp/gametypes/_persistence::setafteractionreportstat("valid", 1); + } + if (isDefined(player.pers["matchesPlayedStatsTracked"])) + { + gamemode = getcurrentgamemode(); + player incrementmatchcompletionstat(gamemode, "played", "completed"); + if (isDefined(player.pers["matchesHostedStatsTracked"])) + { + player incrementmatchcompletionstat(gamemode, "hosted", "completed"); + player.pers["matchesHostedStatsTracked"] = undefined; + } + player.pers["matchesPlayedStatsTracked"] = undefined; + } + recordplayerstats(player, "highestKillStreak", player.pers["best_kill_streak"]); + recordplayerstats(player, "numUavCalled", player maps/mp/killstreaks/_killstreaks::getkillstreakusage("uav_used")); + recordplayerstats(player, "numDogsCalleD", player maps/mp/killstreaks/_killstreaks::getkillstreakusage("dogs_used")); + recordplayerstats(player, "numDogsKills", player.pers["dog_kills"]); + recordplayermatchend(player); + recordplayerstats(player, "presentAtEnd", 1); + } + index++; + } +} + +gamehistoryplayerkicked() +{ + teamscoreratio = self getteamscoreratio(); + scoreboardposition = getplacementforplayer(self); + if (scoreboardposition < 0) scoreboardposition = level.players.size; + self gamehistoryfinishmatch(2, self.kills, self.deaths, self.score, scoreboardposition, teamscoreratio); + if (isDefined(self.pers["matchesPlayedStatsTracked"])) + { + gamemode = getcurrentgamemode(); + self incrementmatchcompletionstat(gamemode, "played", "kicked"); + self.pers["matchesPlayedStatsTracked"] = undefined; + } + uploadstats(self); + wait 1; +} + +gamehistoryplayerquit() +{ + teamscoreratio = self getteamscoreratio(); + scoreboardposition = getplacementforplayer(self); + if (scoreboardposition < 0) + { + scoreboardposition = level.players.size; + } + self gamehistoryfinishmatch(3, self.kills, self.deaths, self.score, scoreboardposition, teamscoreratio); + if (isDefined(self.pers["matchesPlayedStatsTracked"])) + { + gamemode = getcurrentgamemode(); + self incrementmatchcompletionstat(gamemode, "played", "quit"); + if (isDefined(self.pers["matchesHostedStatsTracked"])) + { + self incrementmatchcompletionstat(gamemode, "hosted", "quit"); + self.pers["matchesHostedStatsTracked"] = undefined; + } + self.pers["matchesPlayedStatsTracked"] = undefined; + } + uploadstats(self); + if (!self ishost()) + { + wait 1; + } +} + +displayroundend(winner, endreasontext) +{ + while (level.displayroundendtext) + { + while (level.teambased) + { + if (winner == "tie") + { + maps/mp/_demo::gameresultbookmark("round_result", level.teamindex["neutral"], level.teamindex["neutral"]); + } + else + { + maps/mp/_demo::gameresultbookmark("round_result", level.teamindex[winner], level.teamindex["neutral"]); + } + } + setmatchflag("cg_drawSpectatorMessages", 0); + players = level.players; + index = 0; + while (index < players.size) + { + player = players[index]; + if (!waslastround()) + { + player notify("round_ended"); + } + if (!isDefined(player.pers["team"])) + { + player [[level.spawnintermission]](1); + player closemenu(); + player closeingamemenu(); + } + else + { + if (level.wagermatch) + { + if (level.teambased) + { + player thread [[level.onteamwageroutcomenotify]](winner, 1, endreasontext); + } + else + { + player thread [[level.onwageroutcomenotify]](winner, endreasontext); + } + } + else + { + if (level.teambased) + { + player thread [[level.onteamoutcomenotify]](winner, 1, endreasontext); + player maps/mp/gametypes/_globallogic_audio::set_music_on_player("ROUND_END"); + } + else + { + player thread [[level.onoutcomenotify]](winner, 1, endreasontext); + player maps/mp/gametypes/_globallogic_audio::set_music_on_player("ROUND_END"); + } + } + player setclientuivisibilityflag("hud_visible", 0); + player setclientuivisibilityflag("g_compassShowEnemies", 0); + } + index++; + } + } + if (waslastround()) + { + roundendwait(level.roundenddelay, 0); + } + else + { + thread maps/mp/gametypes/_globallogic_audio::announceroundwinner(winner, level.roundenddelay / 4); + roundendwait(level.roundenddelay, 1); + } +} + +displayroundswitch(winner, endreasontext) +{ + switchtype = level.halftimetype; + if (switchtype == "halftime") + { + if (isDefined(level.nextroundisovertime) && level.nextroundisovertime) + { + switchtype = "overtime"; + } + else + { + if (level.roundlimit) + { + if (game["roundsplayed"] * 2 == level.roundlimit) + { + switchtype = "halftime"; + } + else + { + switchtype = "intermission"; + } + } + else + { + if (level.scorelimit) + { + if (game["roundsplayed"] == level.scorelimit - 1) + { + switchtype = "halftime"; + } + else + { + switchtype = "intermission"; + } + } + else + { + switchtype = "intermission"; + } + } + } + } + leaderdialog = maps/mp/gametypes/_globallogic_audio::getroundswitchdialog(switchtype); + setmatchtalkflag("EveryoneHearsEveryone", 1); + players = level.players; + index = 0; + while (index < players.size) + { + player = players[index]; + if (!isDefined(player.pers["team"])) + { + player [[level.spawnintermission]](1); + player closemenu(); + player closeingamemenu(); + } + else + { + player maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer(leaderdialog); + player maps/mp/gametypes/_globallogic_audio::set_music_on_player("ROUND_SWITCH"); + if (level.wagermatch) + { + player thread [[level.onteamwageroutcomenotify]](switchtype, 1, level.halftimesubcaption); + } + else + { + player thread [[level.onteamoutcomenotify]](switchtype, 0, level.halftimesubcaption); + } + player setclientuivisibilityflag("hud_visible", 0); + } + index++; + } + roundendwait(level.halftimeroundenddelay, 0); +} + +displaygameend(winner, endreasontext) +{ + setmatchtalkflag("EveryoneHearsEveryone", 1); + setmatchflag("cg_drawSpectatorMessages", 0); + while (level.teambased) + { + if (winner == "tie") + { + maps/mp/_demo::gameresultbookmark("game_result", level.teamindex["neutral"], level.teamindex["neutral"]); + } + else + { + maps/mp/_demo::gameresultbookmark("game_result", level.teamindex[winner], level.teamindex["neutral"]); + } + } + players = level.players; + index = 0; + while (index < players.size) + { + player = players[index]; + if (!isDefined(player.pers["team"])) + { + player [[level.spawnintermission]](1); + player closemenu(); + player closeingamemenu(); + } + else + { + if (level.wagermatch) + { + if (level.teambased) + { + player thread [[level.onteamwageroutcomenotify]](winner, 0, endreasontext); + } + else + { + player thread [[level.onwageroutcomenotify]](winner, endreasontext); + } + } + else + { + if (level.teambased) + { + player thread [[level.onteamoutcomenotify]](winner, 0, endreasontext); + } + else + { + player thread [[level.onoutcomenotify]](winner, 0, endreasontext); + if (isDefined(winner) && player == winner) + { + music = game["music"]["victory_" + player.team]; + player maps/mp/gametypes/_globallogic_audio::set_music_on_player(music); + } + else + { + if (!level.splitscreen) + { + player maps/mp/gametypes/_globallogic_audio::set_music_on_player("LOSE"); + } + } + } + } + player setclientuivisibilityflag("hud_visible", 0); + player setclientuivisibilityflag("g_compassShowEnemies", 0); + } + index++; + } + while (level.teambased) + { + thread maps/mp/gametypes/_globallogic_audio::announcegamewinner(winner, level.postroundtime / 2); + players = level.players; + index = 0; + while (index < players.size) + { + player = players[index]; + team = player.pers["team"]; + if (level.splitscreen) + { + if (winner == "tie") + { + player maps/mp/gametypes/_globallogic_audio::set_music_on_player("DRAW"); + } + else + { + if (winner == team) + { + music = game["music"]["victory_" + player.team]; + player maps/mp/gametypes/_globallogic_audio::set_music_on_player(music); + } + else + { + player maps/mp/gametypes/_globallogic_audio::set_music_on_player("LOSE"); + } + } + } + else + { + if (winner == "tie") + { + player maps/mp/gametypes/_globallogic_audio::set_music_on_player("DRAW"); + } + else + { + if (winner == team) + { + music = game["music"]["victory_" + player.team]; + player maps/mp/gametypes/_globallogic_audio::set_music_on_player(music); + } + else + { + player maps/mp/gametypes/_globallogic_audio::set_music_on_player("LOSE"); + } + } + } + index++; + } + } + bbprint("session_epilogs", "reason %s", endreasontext); + bbprint("mpmatchfacts", "gametime %d winner %s killstreakcount %d", getTime(), winner, level.killstreak_counter); + roundendwait(level.postroundtime, 1); +} + +getendreasontext() +{ + while (isDefined(level.endreasontext)) + { + return level.endreasontext; + } + if (hitroundlimit() || hitroundwinlimit()) + { + return game["strings"]["round_limit_reached"]; + } + else + { + if (hitscorelimit()) + { + return game["strings"]["score_limit_reached"]; + } + } + if (level.forcedend) + { + if (level.hostforcedend) + { + return &"MP_HOST_ENDED_GAME"; + } + else + { + return &"MP_ENDED_GAME"; + } + } + return game["strings"]["time_limit_reached"]; +} + +resetoutcomeforallplayers() +{ + players = level.players; + index = 0; + while (index < players.size) + { + player = players[index]; + player notify("reset_outcome"); + index++; + } +} + +startnextround(winner, endreasontext) +{ + if (!isoneround()) + { + displayroundend(winner, endreasontext); + maps/mp/gametypes/_globallogic_utils::executepostroundevents(); + if (!waslastround()) + { + while (checkroundswitch()) + { + displayroundswitch(winner, endreasontext); + } + if (isDefined(level.nextroundisovertime) && level.nextroundisovertime) + { + if (!isDefined(game["overtime_round"])) + { + game["overtime_round"] = 1; + } + else + { + game["overtime_round"]++; + } + } + setmatchtalkflag("DeadChatWithDead", level.voip.deadchatwithdead); + setmatchtalkflag("DeadChatWithTeam", level.voip.deadchatwithteam); + setmatchtalkflag("DeadHearTeamLiving", level.voip.deadhearteamliving); + setmatchtalkflag("DeadHearAllLiving", level.voip.deadhearallliving); + setmatchtalkflag("EveryoneHearsEveryone", level.voip.everyonehearseveryone); + setmatchtalkflag("DeadHearKiller", level.voip.deadhearkiller); + setmatchtalkflag("KillersHearVictim", level.voip.killershearvictim); + game["state"] = "playing"; + level.allowbattlechatter = getgametypesetting("allowBattleChatter"); + map_restart(1); + return 1; + } + } + return 0; +} + +settopplayerstats() +{ + while (level.rankedmatch || level.wagermatch) + { + placement = level.placement["all"]; + topthreeplayers = min(3, placement.size); + index = 0; + while (index < topthreeplayers) + { + if (level.placement["all"][index].score) + { + if (!index) + { + level.placement["all"][index] addplayerstatwithgametype("TOPPLAYER", 1); + level.placement["all"][index] notify("topplayer"); + } + else + { + level.placement["all"][index] notify("nottopplayer"); + } + level.placement["all"][index] addplayerstatwithgametype("TOP3", 1); + level.placement["all"][index] addplayerstat("TOP3ANY", 1); + while (level.hardcoremode) + { + level.placement["all"][index] addplayerstat("TOP3ANY_HC", 1); + } + while (level.multiteam) + { + level.placement["all"][index] addplayerstat("TOP3ANY_MULTITEAM", 1); + } + level.placement["all"][index] notify("top3"); + } + index++; + } + index = 3; + while (index < placement.size) + { + level.placement["all"][index] notify("nottop3"); + level.placement["all"][index] notify("nottopplayer"); + index++; + } + while (level.teambased) + { + _a1500 = level.teams; + _k1500 = getFirstArrayKey(_a1500); + while (isDefined(_k1500)) + { + team = _a1500[_k1500]; + settopteamstats(team); + _k1500 = getNextArrayKey(_a1500, _k1500); + } + } + } +} + +settopteamstats(team) +{ + placementteam = level.placement[team]; + topthreeteamplayers = min(3, placementteam.size); + if (placementteam.size < 5) + { + return; + } + index = 0; + while (index < topthreeteamplayers) + { + while (placementteam[index].score) + { + placementteam[index] addplayerstat("TOP3TEAM", 1); + placementteam[index] addplayerstat("TOP3ANY", 1); + while (level.hardcoremode) + { + placementteam[index] addplayerstat("TOP3ANY_HC", 1); + } + while (level.multiteam) + { + placementteam[index] addplayerstat("TOP3ANY_MULTITEAM", 1); + } + placementteam[index] addplayerstatwithgametype("TOP3TEAM", 1); + } + index++; + } +} + +getgamelength() +{ + if (!(level.timelimit) || level.forcedend) + { + gamelength = maps/mp/gametypes/_globallogic_utils::gettimepassed() / 1000; + gamelength = min(gamelength, 1200); + } + else + { + gamelength = level.timelimit * 60; + } + return gamelength; +} + +endgame(winner, endreasontext) +{ + if (game["state"] == "postgame" || level.gameended) + { + return; + } + if (isDefined(level.onendgame)) + { + [[level.onendgame]](winner); + } + if (!level.wagermatch) + { + setmatchflag("enable_popups", 0); + } + if (!(isDefined(level.disableoutrovisionset)) || level.disableoutrovisionset == 0) + { + if (sessionmodeiszombiesgame() && level.forcedend) + { + visionsetnaked("zombie_last_stand", 2); + } + else + { + visionsetnaked("mpOutro", 2); + } + } + setmatchflag("cg_drawSpectatorMessages", 0); + setmatchflag("game_ended", 1); + game["state"] = "postgame"; + level.gameendtime = getTime(); + level.gameended = 1; + setdvar("g_gameEnded", 1); + level.ingraceperiod = 0; + level notify("game_ended"); + level.allowbattlechatter = 0; + maps/mp/gametypes/_globallogic_audio::flushdialog(); + _a1595 = level.teams; + _k1595 = getFirstArrayKey(_a1595); + while (isDefined(_k1595)) + { + team = _a1595[_k1595]; + game["lastroundscore"][team] = getteamscore(team); + _k1595 = getNextArrayKey(_a1595, _k1595); + } + if (!(isDefined(game["overtime_round"])) || waslastround()) + { + game["roundsplayed"]++; + game["roundwinner"][game["roundsplayed"]] = winner; + if (level.teambased) + { + game["roundswon"][winner]++; + } + } + if (isDefined(winner) && level.teambased && isDefined(level.teams[winner])) + { + level.finalkillcam_winner = winner; + } + else + { + level.finalkillcam_winner = "none"; + } + setgameendtime(0); + updateplacement(); + updaterankedmatch(winner); + players = level.players; + newtime = getTime(); + gamelength = getgamelength(); + setmatchtalkflag("EveryoneHearsEveryone", 1); + bbgameover = 0; + if (isoneround() || waslastround()) + { + bbgameover = 1; + } + index = 0; + while (index < players.size) + { + player = players[index]; + player maps/mp/gametypes/_globallogic_player::freezeplayerforroundend(); + player thread roundenddof(4); + player maps/mp/gametypes/_globallogic_ui::freegameplayhudelems(); + player maps/mp/gametypes/_weapons::updateweapontimings(newtime); + player bbplayermatchend(gamelength, endreasontext, bbgameover); + if (ispregame()) + { + } + else + { + while (level.rankedmatch || level.wagermatch || level.leaguematch && !(player issplitscreen())) + { + if (level.leaguematch) + { + player setdstat("AfterActionReportStats", "lobbyPopup", "leaguesummary"); + } + else + { + if (isDefined(player.setpromotion)) + { + player setdstat("AfterActionReportStats", "lobbyPopup", "promotion"); + } + else + { + player setdstat("AfterActionReportStats", "lobbyPopup", "summary"); + } + } + } + } + index++; + } + maps/mp/_music::setmusicstate("SILENT"); + if (!level.infinalkillcam) + { + } + maps/mp/_gamerep::gamerepupdateinformationforround(); + maps/mp/gametypes/_wager::finalizewagerround(); + thread maps/mp/_challenges::roundend(winner); + if (startnextround(winner, endreasontext)) + { + return; + } + if (!(isoneround()) && !(level.gameforfeited)) + { + if (isDefined(level.onroundendgame)) + { + winner = [[level.onroundendgame]](winner); + } + endreasontext = getendreasontext(); + } + while (!(level.wagermatch) && !(sessionmodeiszombiesgame())) + { + maps/mp/gametypes/_globallogic_score::updatewinlossstats(winner); + } + if (level.teambased) + { + if (winner == "tie") + { + recordgameresult("draw"); + } + else + { + recordgameresult(winner); + } + } + else + { + if (!isDefined(winner)) + { + recordgameresult("draw"); + } + else + { + recordgameresult(winner.team); + } + } + skillupdate(winner, level.teambased); + recordleaguewinner(winner); + settopplayerstats(); + thread maps/mp/_challenges::gameend(winner); + if (!(isDefined(level.skipgameend)) || !(level.skipgameend)) + { + if (isDefined(level.preendgamefunction)) + { + thread [[level.preendgamefunction]](level.postroundtime); + } + displaygameend(winner, endreasontext); + } + if (isoneround()) + { + maps/mp/gametypes/_globallogic_utils::executepostroundevents(); + } + level.intermission = 1; + maps/mp/_gamerep::gamerepanalyzeandreport(); + if (!ispregame()) + { + thread sendafteractionreport(); + } + maps/mp/gametypes/_wager::finalizewagergame(); + setmatchtalkflag("EveryoneHearsEveryone", 1); + players = level.players; + index = 0; + while (index < players.size) + { + player = players[index]; + recordplayerstats(player, "presentAtEnd", 1); + player closemenu(); + player closeingamemenu(); + player notify("reset_outcome"); + player thread [[level.spawnintermission]](); + player setclientuivisibilityflag("hud_visible", 1); + index++; + } + if (isDefined(level.endgamefunction)) + { + level thread [[level.endgamefunction]](); + } + level notify("sfade"); + logstring("game ended"); + if (!(isDefined(level.skipgameend)) || !(level.skipgameend)) + { + wait 5; + } + exitlevel(0); +} + +bbplayermatchend(gamelength, endreasonstring, gameover) +{ + playerrank = getplacementforplayer(self); + totaltimeplayed = 0; + if (isDefined(self.timeplayed) && isDefined(self.timeplayed["total"])) + { + totaltimeplayed = self.timeplayed["total"]; + if (totaltimeplayed > gamelength) + { + totaltimeplayed = gamelength; + } + } + xuid = self getxuid(); + bbprint("mpplayermatchfacts", "score %d momentum %d endreason %s sessionrank %d playtime %d xuid %s gameover %d team %s", self.pers["score"], self.pers["momentum"], endreasonstring, playerrank, totaltimeplayed, xuid, gameover, self.pers["team"]); +} + +roundendwait(defaultdelay, matchbonus) +{ + notifiesdone = 0; + if (!notifiesdone) + { + players = level.players; + notifiesdone = 1; + index = 0; + while (index < players.size) + { + if (!(isDefined(players[index].doingnotify)) || !(players[index].doingnotify)) + { + } + else + { + notifiesdone = 0; + } + index++; + } + wait 0.5; + } + if (!matchbonus) + { + wait defaultdelay; + level notify("round_end_done"); + return; + } + wait defaultdelay / 2; + level notify("give_match_bonus"); + wait defaultdelay / 2; + notifiesdone = 0; + if (!notifiesdone) + { + players = level.players; + notifiesdone = 1; + index = 0; + while (index < players.size) + { + if (!(isDefined(players[index].doingnotify)) || !(players[index].doingnotify)) + { + } + else + { + notifiesdone = 0; + } + index++; + } + wait 0.5; + } + level notify("round_end_done"); +} + +roundenddof(time) +{ + self setdepthoffield(0, 128, 512, 4000, 6, 1.8); +} + +checktimelimit() +{ + if (isDefined(level.timelimitoverride) && level.timelimitoverride) + { + return; + } + if (game["state"] != "playing") + { + setgameendtime(0); + return; + } + if (level.timelimit <= 0) + { + setgameendtime(0); + return; + } + if (level.inprematchperiod) + { + setgameendtime(0); + return; + } + if (level.timerstopped) + { + setgameendtime(0); + return; + } + if (!isDefined(level.starttime)) + { + return; + } + timeleft = maps/mp/gametypes/_globallogic_utils::gettimeremaining(); + setgameendtime(getTime() + int(timeleft)); + if (timeleft > 0) + { + return; + } + [[level.ontimelimit]](); +} + +allteamsunderscorelimit() +{ + _a1917 = level.teams; + _k1917 = getFirstArrayKey(_a1917); + while (isDefined(_k1917)) + { + team = _a1917[_k1917]; + if (game["teamScores"][team] >= level.scorelimit) + { + return 0; + } + _k1917 = getNextArrayKey(_a1917, _k1917); + } + return 1; +} + +checkscorelimit() +{ + if (game["state"] != "playing") + { + return 0; + } + if (level.scorelimit <= 0) + { + return 0; + } + if (level.teambased) + { + if (allteamsunderscorelimit()) + { + return 0; + } + } + else + { + if (!isplayer(self)) + { + return 0; + } + if (self.pointstowin < level.scorelimit) + { + return 0; + } + } + [[level.onscorelimit]](); +} + +updategametypedvars() +{ + level endon("game_ended"); + while (game["state"] == "playing") + { + roundlimit = clamp(getgametypesetting("roundLimit"), level.roundlimitmin, level.roundlimitmax); + if (roundlimit != level.roundlimit) + { + level.roundlimit = roundlimit; + level notify("update_roundlimit"); + } + timelimit = [[level.gettimelimit]](); + if (timelimit != level.timelimit) + { + level.timelimit = timelimit; + setdvar("ui_timelimit", level.timelimit); + level notify("update_timelimit"); + } + thread checktimelimit(); + scorelimit = clamp(getgametypesetting("scoreLimit"), level.scorelimitmin, level.scorelimitmax); + if (scorelimit != level.scorelimit) + { + level.scorelimit = scorelimit; + setdvar("ui_scorelimit", level.scorelimit); + level notify("update_scorelimit"); + } + thread checkscorelimit(); + while (isDefined(level.starttime)) + { + while (maps/mp/gametypes/_globallogic_utils::gettimeremaining() < 3000) + { + wait 0.1; + } + } + wait 1; + } +} + +removedisconnectedplayerfromplacement() +{ + offset = 0; + numplayers = level.placement["all"].size; + found = 0; + i = 0; + while (i < numplayers) + { + if (level.placement["all"][i] == self) + { + found = 1; + } + if (found) + { + level.placement["all"][i] = level.placement["all"][i + 1]; + } + i++; + } + if (!found) + { + return; + } + level.placement["all"][numplayers - 1] = undefined; + updateteamplacement(); + if (level.teambased) + { + return; + } + numplayers = level.placement["all"].size; + i = 0; + while (i < numplayers) + { + player = level.placement["all"][i]; + player notify("update_outcome"); + i++; + } +} + +updateplacement() +{ + if (!level.players.size) + { + return; + } + level.placement["all"] = []; + index = 0; + while (index < level.players.size) + { + if (isDefined(level.teams[level.players[index].team])) + { + level.placement["all"][level.placement["all"].size] = level.players[index]; + } + index++; + } + placementall = level.placement["all"]; + if (level.teambased) + { + i = 1; + while (i < placementall.size) + { + player = placementall[i]; + playerscore = player.score; + j = i - 1; + while (j >= 0 && playerscore > placementall[j].score || playerscore == placementall[j].score && player.deaths < placementall[j].deaths) + { + placementall[j + 1] = placementall[j]; + j--; + } + placementall[j + 1] = player; + i++; + } + } + else + { + i = 1; + while (i < placementall.size) + { + player = placementall[i]; + playerscore = player.pointstowin; + j = i - 1; + while (j >= 0 && playerscore > placementall[j].pointstowin || playerscore == placementall[j].pointstowin && player.deaths < placementall[j].deaths) + { + placementall[j + 1] = placementall[j]; + j--; + } + placementall[j + 1] = player; + i++; + } + } + level.placement["all"] = placementall; + updateteamplacement(); +} + +updateteamplacement() +{ + _a2085 = level.teams; + _k2085 = getFirstArrayKey(_a2085); + while (isDefined(_k2085)) + { + team = _a2085[_k2085]; + placement[team] = []; + _k2085 = getNextArrayKey(_a2085, _k2085); + } + placement["spectator"] = []; + if (!level.teambased) + { + return; + } + placementall = level.placement["all"]; + placementallsize = placementall.size; + i = 0; + while (i < placementallsize) + { + player = placementall[i]; + team = player.pers["team"]; + placement[team][placement[team].size] = player; + i++; + } + _a2105 = level.teams; + _k2105 = getFirstArrayKey(_a2105); + while (isDefined(_k2105)) + { + team = _a2105[_k2105]; + level.placement[team] = placement[team]; + _k2105 = getNextArrayKey(_a2105, _k2105); + } +} + +getplacementforplayer(player) +{ + updateplacement(); + playerrank = -1; + placement = level.placement["all"]; + placementindex = 0; + while (placementindex < placement.size) + { + if (level.placement["all"][placementindex] == player) + { + playerrank = placementindex + 1; + } + else + { + placementindex++; + } + } + return playerrank; +} + +istopscoringplayer(player) +{ + topplayer = 0; + updateplacement(); + if (level.placement["all"].size == 0) + { + return 0; + } + if (level.teambased) + { + topscore = level.placement["all"][0].score; + index = 0; + while (index < level.placement["all"].size) + { + if (level.placement["all"][index].score == 0) + { + } + else + { + if (topscore > level.placement["all"][index].score) + { + } + else + { + if (self == level.placement["all"][index]) + { + topscoringplayer = 1; + } + else + { + index++; + } + } + } + } + } + else + { + topscore = level.placement["all"][0].pointstowin; + index = 0; + while (index < level.placement["all"].size) + { + if (level.placement["all"][index].pointstowin == 0) + { + } + else + { + if (topscore > level.placement["all"][index].pointstowin) + { + } + else + { + if (self == level.placement["all"][index]) + { + topplayer = 1; + } + else + { + index++; + } + } + } + } + } + return topplayer; +} + +sortdeadplayers(team) +{ + if (!level.playerqueuedrespawn) + { + return; + } + i = 1; + while (i < level.deadplayers[team].size) + { + player = level.deadplayers[team][i]; + j = i - 1; + while (j >= 0 && player.deathtime < level.deadplayers[team][j].deathtime) + { + level.deadplayers[team][j + 1] = level.deadplayers[team][j]; + j--; + } + level.deadplayers[team][j + 1] = player; + i++; + } + i = 0; + while (i < level.deadplayers[team].size) + { + if (level.deadplayers[team][i].spawnqueueindex != i) + { + level.spawnqueuemodified[team] = 1; + } + level.deadplayers[team][i].spawnqueueindex = i; + i++; + } +} + +totalalivecount() +{ + count = 0; + _a2211 = level.teams; + _k2211 = getFirstArrayKey(_a2211); + while (isDefined(_k2211)) + { + team = _a2211[_k2211]; + count = count + level.alivecount[team]; + _k2211 = getNextArrayKey(_a2211, _k2211); + } + return count; +} + +totalplayerlives() +{ + count = 0; + _a2221 = level.teams; + _k2221 = getFirstArrayKey(_a2221); + while (isDefined(_k2221)) + { + team = _a2221[_k2221]; + count = count + level.playerlives[team]; + _k2221 = getNextArrayKey(_a2221, _k2221); + } + return count; +} + +totalplayercount() +{ + count = 0; + _a2231 = level.teams; + _k2231 = getFirstArrayKey(_a2231); + while (isDefined(_k2231)) + { + team = _a2231[_k2231]; + count = count + level.playercount[team]; + _k2231 = getNextArrayKey(_a2231, _k2231); + } + return count; +} + +initteamvariables(team) +{ + if (!isDefined(level.alivecount)) + { + level.alivecount = []; + } + level.alivecount[team] = 0; + level.lastalivecount[team] = 0; + if (!isDefined(game["everExisted"])) + { + game["everExisted"] = []; + } + if (!isDefined(game["everExisted"][team])) + { + game["everExisted"][team] = 0; + } + level.everexisted[team] = 0; + level.wavedelay[team] = 0; + level.lastwave[team] = 0; + level.waveplayerspawnindex[team] = 0; + resetteamvariables(team); +} + +resetteamvariables(team) +{ + level.playercount[team] = 0; + level.botscount[team] = 0; + level.lastalivecount[team] = level.alivecount[team]; + level.alivecount[team] = 0; + level.playerlives[team] = 0; + level.aliveplayers[team] = []; + level.deadplayers[team] = []; + level.squads[team] = []; + level.spawnqueuemodified[team] = 0; +} + +updateteamstatus() +{ + level notify("updating_team_status"); + level endon("updating_team_status"); + level endon("game_ended"); + waitTillFrameEnd; + wait 0; + if (game["state"] == "postgame") + { + return; + } + resettimeout(); + _a2291 = level.teams; + _k2291 = getFirstArrayKey(_a2291); + while (isDefined(_k2291)) + { + team = _a2291[_k2291]; + resetteamvariables(team); + _k2291 = getNextArrayKey(_a2291, _k2291); + } + level.activeplayers = []; + players = level.players; + i = 0; + while (i < players.size) + { + player = players[i]; + if (!(isDefined(player)) && level.splitscreen) + { + } + else + { + team = player.team; + class = player.class; + if (team != "spectator" && isDefined(class) && class != "") + { + level.playercount[team]++; + if (isDefined(player.pers["isBot"])) + { + level.botscount[team]++; + } + if (player.sessionstate == "playing") + { + level.alivecount[team]++; + level.playerlives[team]++; + player.spawnqueueindex = -1; + if (isalive(player)) + { + level.aliveplayers[team][level.aliveplayers[team].size] = player; + level.activeplayers[level.activeplayers.size] = player; + } + else + { + level.deadplayers[team][level.deadplayers[team].size] = player; + } + } + else + { + level.deadplayers[team][level.deadplayers[team].size] = player; + if (player maps/mp/gametypes/_globallogic_spawn::mayspawn()) + { + level.playerlives[team]++; + } + } + } + } + i++; + } + totalalive = totalalivecount(); + if (totalalive > level.maxplayercount) + { + level.maxplayercount = totalalive; + } + _a2346 = level.teams; + _k2346 = getFirstArrayKey(_a2346); + while (isDefined(_k2346)) + { + team = _a2346[_k2346]; + if (level.alivecount[team]) + { + game["everExisted"][team] = 1; + level.everexisted[team] = 1; + } + sortdeadplayers(team); + _k2346 = getNextArrayKey(_a2346, _k2346); + } + level updategameevents(); +} + +checkteamscorelimitsoon(team) +{ + if (level.scorelimit <= 0) + { + return; + } + if (!level.teambased) + { + return; + } + if (maps/mp/gametypes/_globallogic_utils::gettimepassed() < 60000) + { + return; + } + timeleft = maps/mp/gametypes/_globallogic_utils::getestimatedtimeuntilscorelimit(team); + if (timeleft < 1) + { + level notify("match_ending_soon", "score"); + } +} + +checkplayerscorelimitsoon() +{ + if (level.scorelimit <= 0) + { + return; + } + if (level.teambased) + { + return; + } + if (maps/mp/gametypes/_globallogic_utils::gettimepassed() < 60000) + { + return; + } + timeleft = maps/mp/gametypes/_globallogic_utils::getestimatedtimeuntilscorelimit(undefined); + if (timeleft < 1) + { + level notify("match_ending_soon", "score"); + } +} + +timelimitclock() +{ + level endon("game_ended"); + wait 0.05; + clockobject = spawn("script_origin", (0, 0, 0)); + while (game["state"] == "playing") + { + if (!(level.timerstopped) && level.timelimit) + { + timeleft = maps/mp/gametypes/_globallogic_utils::gettimeremaining() / 1000; + timeleftint = int(timeleft + 0.5); + if (timeleftint == 601) + { + clientnotify("notify_10"); + } + if (timeleftint == 301) + { + clientnotify("notify_5"); + } + if (timeleftint == 60) + { + clientnotify("notify_1"); + } + if (timeleftint == 12) + { + clientnotify("notify_count"); + } + if (timeleftint >= 40 && timeleftint <= 60) + { + level notify("match_ending_soon", "time"); + } + if (timeleftint >= 30 && timeleftint <= 40) + { + level notify("match_ending_pretty_soon", "time"); + } + if (timeleftint <= 32) + { + level notify("match_ending_vox"); + } + if (timeleftint <= 10 || timeleftint <= 30 && timeleftint % 2 == 0) + { + level notify("match_ending_very_soon", "time"); + if (timeleftint == 0) + { + } + else + { + clockobject playsound("mpl_ui_timer_countdown"); + } + if (timeleft - floor(timeleft) >= 0.05) + { + wait timeleft - floor(timeleft); + } + } + wait 1; + } + } +} + +timelimitclock_intermission(waittime) +{ + setgameendtime(getTime() + int(waittime * 1000)); + clockobject = spawn("script_origin", (0, 0, 0)); + if (waittime >= 10) + { + wait waittime - 10; + } + clockobject playsound("mpl_ui_timer_countdown"); + wait 1; +} + +startgame() +{ + thread maps/mp/gametypes/_globallogic_utils::gametimer(); + level.timerstopped = 0; + setmatchtalkflag("DeadChatWithDead", level.voip.deadchatwithdead); + setmatchtalkflag("DeadChatWithTeam", level.voip.deadchatwithteam); + setmatchtalkflag("DeadHearTeamLiving", level.voip.deadhearteamliving); + setmatchtalkflag("DeadHearAllLiving", level.voip.deadhearallliving); + setmatchtalkflag("EveryoneHearsEveryone", level.voip.everyonehearseveryone); + setmatchtalkflag("DeadHearKiller", level.voip.deadhearkiller); + setmatchtalkflag("KillersHearVictim", level.voip.killershearvictim); + prematchperiod(); + level notify("prematch_over"); + thread timelimitclock(); + thread graceperiod(); + thread watchmatchendingsoon(); + thread maps/mp/gametypes/_globallogic_audio::musiccontroller(); + recordmatchbegin(); +} + +waitforplayers() +{ + starttime = getTime(); + while (getnumconnectedplayers() < 1) + { + wait 0.05; + while (getTime() - starttime > 120000) + { + exitlevel(0); + } + } +} + +prematchperiod() +{ + setmatchflag("hud_hardcore", level.hardcoremode); + level endon("game_ended"); + if (level.prematchperiod > 0) + { + thread matchstarttimer(); + waitforplayers(); + wait level.prematchperiod; + } + else + { + matchstarttimerskip(); + wait 0.05; + } + level.inprematchperiod = 0; + index = 0; + while (index < level.players.size) + { + level.players[index] freeze_player_controls(0); + level.players[index] enableweapons(); + index++; + } + maps/mp/gametypes/_wager::prematchperiod(); + if (game["state"] != "playing") + { + return; + } +} + +graceperiod() +{ + level endon("game_ended"); + if (isDefined(level.graceperiodfunc)) + { + [[level.graceperiodfunc]](); + } + else + { + wait level.graceperiod; + } + level notify("grace_period_ending"); + wait 0.05; + level.ingraceperiod = 0; + if (game["state"] != "playing") + { + return; + } + while (level.numlives) + { + players = level.players; + i = 0; + while (i < players.size) + { + player = players[i]; + while (!(player.hasspawned) && player.sessionteam != "spectator" && !(isalive(player))) + { + player.statusicon = "hud_status_dead"; + } + i++; + } + } + level thread updateteamstatus(); +} + +watchmatchendingsoon() +{ + setdvar("xblive_matchEndingSoon", 0); + level waittill("match_ending_soon", reason); + setdvar("xblive_matchEndingSoon", 1); +} + +assertteamvariables() +{ + while (!(level.createfx_enabled) && !(sessionmodeiszombiesgame())) + { + _a2604 = level.teams; + _k2604 = getFirstArrayKey(_a2604); + while (isDefined(_k2604)) + { + team = _a2604[_k2604]; + _k2604 = getNextArrayKey(_a2604, _k2604); + } + } +} + +anyteamhaswavedelay() +{ + _a2622 = level.teams; + _k2622 = getFirstArrayKey(_a2622); + while (isDefined(_k2622)) + { + team = _a2622[_k2622]; + if (level.wavedelay[team]) + { + return 1; + } + _k2622 = getNextArrayKey(_a2622, _k2622); + } + return 0; +} + +callback_startgametype() +{ + level.prematchperiod = 0; + level.intermission = 0; + setmatchflag("cg_drawSpectatorMessages", 1); + setmatchflag("game_ended", 0); + if (!isDefined(game["gamestarted"])) + { + if (!isDefined(game["allies"])) + { + game["allies"] = "seals"; + } + if (!isDefined(game["axis"])) + { + game["axis"] = "pmc"; + } + if (!isDefined(game["attackers"])) + { + game["attackers"] = "allies"; + } + if (!isDefined(game["defenders"])) + { + game["defenders"] = "axis"; + } + _a2655 = level.teams; + _k2655 = getFirstArrayKey(_a2655); + while (isDefined(_k2655)) + { + team = _a2655[_k2655]; + if (!isDefined(game[team])) + { + game[team] = "pmc"; + } + _k2655 = getNextArrayKey(_a2655, _k2655); + } + if (!isDefined(game["state"])) + { + game["state"] = "playing"; + } + precacherumble("damage_heavy"); + precacherumble("damage_light"); + precacheshader("white"); + precacheshader("black"); + makedvarserverinfo("scr_allies", "marines"); + makedvarserverinfo("scr_axis", "nva"); + makedvarserverinfo("cg_thirdPersonAngle", 354); + setdvar("cg_thirdPersonAngle", 354); + game["strings"]["press_to_spawn"] = &"PLATFORM_PRESS_TO_SPAWN"; + if (level.teambased) + { + game["strings"]["waiting_for_teams"] = &"MP_WAITING_FOR_TEAMS"; + game["strings"]["opponent_forfeiting_in"] = &"MP_OPPONENT_FORFEITING_IN"; + } + else + { + game["strings"]["waiting_for_teams"] = &"MP_WAITING_FOR_PLAYERS"; + game["strings"]["opponent_forfeiting_in"] = &"MP_OPPONENT_FORFEITING_IN"; + } + game["strings"]["match_starting_in"] = &"MP_MATCH_STARTING_IN"; + game["strings"]["spawn_next_round"] = &"MP_SPAWN_NEXT_ROUND"; + game["strings"]["waiting_to_spawn"] = &"MP_WAITING_TO_SPAWN"; + game["strings"]["waiting_to_spawn_ss"] = &"MP_WAITING_TO_SPAWN_SS"; + game["strings"]["you_will_spawn"] = &"MP_YOU_WILL_RESPAWN"; + game["strings"]["match_starting"] = &"MP_MATCH_STARTING"; + game["strings"]["change_class"] = &"MP_CHANGE_CLASS_NEXT_SPAWN"; + game["strings"]["last_stand"] = &"MPUI_LAST_STAND"; + game["strings"]["cowards_way"] = &"PLATFORM_COWARDS_WAY_OUT"; + game["strings"]["tie"] = &"MP_MATCH_TIE"; + game["strings"]["round_draw"] = &"MP_ROUND_DRAW"; + game["strings"]["enemies_eliminated"] = &"MP_ENEMIES_ELIMINATED"; + game["strings"]["score_limit_reached"] = &"MP_SCORE_LIMIT_REACHED"; + game["strings"]["round_limit_reached"] = &"MP_ROUND_LIMIT_REACHED"; + game["strings"]["time_limit_reached"] = &"MP_TIME_LIMIT_REACHED"; + game["strings"]["players_forfeited"] = &"MP_PLAYERS_FORFEITED"; + game["strings"]["other_teams_forfeited"] = &"MP_OTHER_TEAMS_FORFEITED"; + assertteamvariables(); + [[level.onprecachegametype]](); + game["gamestarted"] = 1; + game["totalKills"] = 0; + _a2718 = level.teams; + _k2718 = getFirstArrayKey(_a2718); + while (isDefined(_k2718)) + { + team = _a2718[_k2718]; + game["teamScores"][team] = 0; + game["totalKillsTeam"][team] = 0; + _k2718 = getNextArrayKey(_a2718, _k2718); + } + if (!ispregame()) + { + level.prematchperiod = getgametypesetting("prematchperiod"); + } + if (getDvarInt(#"0x1e0679b9") != 0) + { + _a2730 = level.teams; + _k2730 = getFirstArrayKey(_a2730); + while (isDefined(_k2730)) + { + team = _a2730[_k2730]; + game["icons"][team] = "composite_emblem_team_axis"; + _k2730 = getNextArrayKey(_a2730, _k2730); + } + game["icons"]["allies"] = "composite_emblem_team_allies"; + game["icons"]["axis"] = "composite_emblem_team_axis"; + } + } + else + { + if (!level.splitscreen) + { + level.prematchperiod = getgametypesetting("preroundperiod"); + } + } + if (!isDefined(game["timepassed"])) + { + game["timepassed"] = 0; + } + if (!isDefined(game["roundsplayed"])) + { + game["roundsplayed"] = 0; + } + setroundsplayed(game["roundsplayed"]); + if (isDefined(game["overtime_round"])) + { + setmatchflag("overtime", 1); + } + else + { + setmatchflag("overtime", 0); + } + if (!isDefined(game["roundwinner"])) + { + game["roundwinner"] = []; + } + if (!isDefined(game["lastroundscore"])) + { + game["lastroundscore"] = []; + } + if (!isDefined(game["roundswon"])) + { + game["roundswon"] = []; + } + if (!isDefined(game["roundswon"]["tie"])) + { + game["roundswon"]["tie"] = 0; + } + _a2773 = level.teams; + _k2773 = getFirstArrayKey(_a2773); + while (isDefined(_k2773)) + { + team = _a2773[_k2773]; + if (!isDefined(game["roundswon"][team])) + { + game["roundswon"][team] = 0; + } + level.teamspawnpoints[team] = []; + level.spawn_point_team_class_names[team] = []; + _k2773 = getNextArrayKey(_a2773, _k2773); + } + level.skipvote = 0; + level.gameended = 0; + setdvar("g_gameEnded", 0); + level.objidstart = 0; + level.forcedend = 0; + level.hostforcedend = 0; + level.hardcoremode = getgametypesetting("hardcoreMode"); + while (level.hardcoremode) + { + logstring("game mode: hardcore"); + if (!isDefined(level.friendlyfiredelaytime)) + { + level.friendlyfiredelaytime = 0; + } + } + if (getDvar(#"0xd16d59fd") == "") + { + setdvar("scr_max_rank", "0"); + } + level.rankcap = getDvarInt(#"0xd16d59fd"); + if (getDvar(#"0x4ebe2cf2") == "") + { + setdvar("scr_min_prestige", "0"); + } + level.minprestige = getDvarInt(#"0x4ebe2cf2"); + level.usestartspawns = 1; + level.roundscorecarry = getgametypesetting("roundscorecarry"); + level.allowhitmarkers = getgametypesetting("allowhitmarkers"); + level.playerqueuedrespawn = getgametypesetting("playerQueuedRespawn"); + level.playerforcerespawn = getgametypesetting("playerForceRespawn"); + level.roundstartexplosivedelay = getgametypesetting("roundStartExplosiveDelay"); + level.roundstartkillstreakdelay = getgametypesetting("roundStartKillstreakDelay"); + level.perksenabled = getgametypesetting("perksEnabled"); + level.disableattachments = getgametypesetting("disableAttachments"); + level.disabletacinsert = getgametypesetting("disableTacInsert"); + level.disablecac = getgametypesetting("disableCAC"); + level.disableclassselection = getgametypesetting("disableClassSelection"); + level.disableweapondrop = getgametypesetting("disableweapondrop"); + level.onlyheadshots = getgametypesetting("onlyHeadshots"); + level.minimumallowedteamkills = getgametypesetting("teamKillPunishCount") - 1; + level.teamkillreducedpenalty = getgametypesetting("teamKillReducedPenalty"); + level.teamkillpointloss = getgametypesetting("teamKillPointLoss"); + level.teamkillspawndelay = getgametypesetting("teamKillSpawnDelay"); + level.deathpointloss = getgametypesetting("deathPointLoss"); + level.leaderbonus = getgametypesetting("leaderBonus"); + level.forceradar = getgametypesetting("forceRadar"); + level.playersprinttime = getgametypesetting("playerSprintTime"); + level.bulletdamagescalar = getgametypesetting("bulletDamageScalar"); + level.playermaxhealth = getgametypesetting("playerMaxHealth"); + level.playerhealthregentime = getgametypesetting("playerHealthRegenTime"); + level.playerrespawndelay = getgametypesetting("playerRespawnDelay"); + level.playerobjectiveheldrespawndelay = getgametypesetting("playerObjectiveHeldRespawnDelay"); + level.waverespawndelay = getgametypesetting("waveRespawnDelay"); + level.suicidespawndelay = getgametypesetting("spawnsuicidepenalty"); + level.teamkilledspawndelay = getgametypesetting("spawnteamkilledpenalty"); + level.maxsuicidesbeforekick = getgametypesetting("maxsuicidesbeforekick"); + level.spectatetype = getgametypesetting("spectateType"); + level.voip = spawnstruct(); + level.voip.deadchatwithdead = getgametypesetting("voipDeadChatWithDead"); + level.voip.deadchatwithteam = getgametypesetting("voipDeadChatWithTeam"); + level.voip.deadhearallliving = getgametypesetting("voipDeadHearAllLiving"); + level.voip.deadhearteamliving = getgametypesetting("voipDeadHearTeamLiving"); + level.voip.everyonehearseveryone = getgametypesetting("voipEveryoneHearsEveryone"); + level.voip.deadhearkiller = getgametypesetting("voipDeadHearKiller"); + level.voip.killershearvictim = getgametypesetting("voipKillersHearVictim"); + if (getDvar(#"0xf7b30924") == "1") + { + level waittill("eternity"); + } + if (sessionmodeiszombiesgame()) + { + level.prematchperiod = 0; + level.persistentdatainfo = []; + level.maxrecentstats = 10; + level.maxhitlocations = 19; + level.globalshotsfired = 0; + thread maps/mp/gametypes/_hud::init(); + thread maps/mp/gametypes/_serversettings::init(); + thread maps/mp/gametypes/_clientids::init(); + thread maps/mp/gametypes/_weaponobjects::init(); + thread maps/mp/gametypes/_scoreboard::init(); + thread maps/mp/gametypes/_killcam::init(); + thread maps/mp/gametypes/_shellshock::init(); + thread maps/mp/gametypes/_deathicons::init(); + thread maps/mp/gametypes/_spectating::init(); + thread maps/mp/gametypes/_objpoints::init(); + thread maps/mp/gametypes/_gameobjects::init(); + thread maps/mp/gametypes/_spawnlogic::init(); + thread maps/mp/gametypes/_globallogic_audio::init(); + thread maps/mp/gametypes/_wager::init(); + thread maps/mp/bots/_bot::init(); + thread maps/mp/_decoy::init(); + } + else + { + thread maps/mp/gametypes/_persistence::init(); + thread maps/mp/gametypes/_menus::init(); + thread maps/mp/gametypes/_hud::init(); + thread maps/mp/gametypes/_serversettings::init(); + thread maps/mp/gametypes/_clientids::init(); + thread maps/mp/teams/_teams::init(); + thread maps/mp/gametypes/_weapons::init(); + thread maps/mp/gametypes/_scoreboard::init(); + thread maps/mp/gametypes/_killcam::init(); + thread maps/mp/gametypes/_shellshock::init(); + thread maps/mp/gametypes/_deathicons::init(); + thread maps/mp/gametypes/_damagefeedback::init(); + thread maps/mp/gametypes/_healthoverlay::init(); + thread maps/mp/gametypes/_spectating::init(); + thread maps/mp/gametypes/_objpoints::init(); + thread maps/mp/gametypes/_gameobjects::init(); + thread maps/mp/gametypes/_spawnlogic::init(); + thread maps/mp/gametypes/_battlechatter_mp::init(); + thread maps/mp/killstreaks/_killstreaks::init(); + thread maps/mp/gametypes/_globallogic_audio::init(); + thread maps/mp/gametypes/_wager::init(); + thread maps/mp/bots/_bot::init(); + thread maps/mp/_decoy::init(); + thread maps/mp/_bb::init(); + } + if (level.teambased) + { + thread maps/mp/gametypes/_friendicons::init(); + } + thread maps/mp/gametypes/_hud_message::init(); + thread maps/mp/_multi_extracam::init(); + stringnames = getarraykeys(game["strings"]); + index = 0; + while (index < stringnames.size) + { + precachestring(game["strings"][stringnames][index]); + index++; + } + _a2939 = level.teams; + _k2939 = getFirstArrayKey(_a2939); + while (isDefined(_k2939)) + { + team = _a2939[_k2939]; + initteamvariables(team); + _k2939 = getNextArrayKey(_a2939, _k2939); + } + level.maxplayercount = 0; + level.activeplayers = []; + level.allowannouncer = getgametypesetting("allowAnnouncer"); + if (!isDefined(level.timelimit)) + { + registertimelimit(1, 1440); + } + if (!isDefined(level.scorelimit)) + { + registerscorelimit(1, 500); + } + if (!isDefined(level.roundlimit)) + { + registerroundlimit(0, 10); + } + if (!isDefined(level.roundwinlimit)) + { + registerroundwinlimit(0, 10); + } + maps/mp/gametypes/_globallogic_utils::registerpostroundevent(::postroundfinalkillcam); + maps/mp/gametypes/_globallogic_utils::registerpostroundevent(::postroundsidebet); + makedvarserverinfo("ui_scorelimit"); + makedvarserverinfo("ui_timelimit"); + makedvarserverinfo("ui_allow_classchange", getDvar(#"0x53e50c7c")); + wavedelay = level.waverespawndelay; + if (wavedelay && !(ispregame())) + { + _a2972 = level.teams; + _k2972 = getFirstArrayKey(_a2972); + while (isDefined(_k2972)) + { + team = _a2972[_k2972]; + level.wavedelay[team] = wavedelay; + level.lastwave[team] = 0; + _k2972 = getNextArrayKey(_a2972, _k2972); + } + level thread [[level.wavespawntimer]](); + } + level.inprematchperiod = 1; + if (level.prematchperiod > 2) + { + level.prematchperiod = level.prematchperiod + randomfloat(4) - 2; + } + if (level.numlives || anyteamhaswavedelay() || level.playerqueuedrespawn) + { + level.graceperiod = 15; + } + else + { + level.graceperiod = 5; + } + level.ingraceperiod = 1; + level.roundenddelay = 5; + level.halftimeroundenddelay = 3; + maps/mp/gametypes/_globallogic_score::updateallteamscores(); + level.killstreaksenabled = 1; + if (getDvar(#"0xdfd7387c") == "") + { + setdvar("scr_game_rankenabled", 1); + } + level.rankenabled = getDvarInt(#"0xdfd7387c"); + if (getDvar(#"0x273f6466") == "") + { + setdvar("scr_game_medalsenabled", 1); + } + level.medalsenabled = getDvarInt(#"0x273f6466"); + if (level.hardcoremode && level.rankedmatch && getDvar(#"0x9c756af7") == "") + { + setdvar("scr_game_friendlyFireDelay", 1); + } + level.friendlyfiredelay = getDvarInt(#"0x9c756af7"); + if (getDvar(#"0x134d5297") == "") + { + [[level.onstartgametype]](); + } + while (getDvarInt(#"0x826eb3b9") == 1) + { + level.killstreaksenabled = 0; + } + level thread maps/mp/gametypes/_killcam::dofinalkillcam(); + thread startgame(); + level thread updategametypedvars(); +} + +forcedebughostmigration() +{} + +registerfriendlyfiredelay(dvarstring, defaultvalue, minvalue, maxvalue) +{ + dvarstring = "scr_" + dvarstring + "_friendlyFireDelayTime"; + if (getDvar(#"dvarstring") == "") + { + setdvar(dvarstring, defaultvalue); + } + if (getDvarInt(#"dvarstring") > maxvalue) + { + setdvar(dvarstring, maxvalue); + } + else + { + if (getDvarInt(#"dvarstring") < minvalue) + { + setdvar(dvarstring, minvalue); + } + } + level.friendlyfiredelaytime = getDvarInt(#"dvarstring"); +} + +checkroundswitch() +{ + if (!(isDefined(level.roundswitch)) || !(level.roundswitch)) + { + return 0; + } + if (!isDefined(level.onroundswitch)) + { + return 0; + } + if (game["roundsplayed"] % level.roundswitch == 0) + { + [[level.onroundswitch]](); + return 1; + } + return 0; +} + +listenforgameend() +{ + self waittill("host_sucks_end_game"); + level.skipvote = 1; + if (!level.gameended) + { + level thread maps/mp/gametypes/_globallogic::forceend(1); + } +} + +getkillstreaks(player) +{ + killstreaknum = 0; + while (killstreaknum < level.maxkillstreaks) + { + killstreak[killstreaknum] = "killstreak_null"; + killstreaknum++; + } + while (isplayer(player) && !(level.oldschool) && level.disableclassselection != 1 && !(isDefined(player.pers["isBot"])) && isDefined(player.killstreak)) + { + currentkillstreak = 0; + killstreaknum = 0; + while (killstreaknum < level.maxkillstreaks) + { + if (isDefined(player.killstreak[killstreaknum])) + { + killstreak[currentkillstreak] = player.killstreak[killstreaknum]; + currentkillstreak++; + } + killstreaknum++; + } + } + return killstreak; +} + +updaterankedmatch(winner) +{ + if (level.rankedmatch) + { + if (hostidledout()) + { + level.hostforcedend = 1; + logstring("host idled out"); + endlobby(); + } + } + if (!(level.wagermatch) && !(sessionmodeiszombiesgame())) + { + maps/mp/gametypes/_globallogic_score::updatematchbonusscores(winner); + } +} + +//GLOBALLOGIC.GSC - Black Ops 2 GSC \ No newline at end of file diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic_actor.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic_actor.gsc new file mode 100644 index 0000000..08518fb --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic_actor.gsc @@ -0,0 +1,207 @@ +#include maps/mp/_challenges; +#include maps/mp/gametypes_zm/_damagefeedback; +#include maps/mp/gametypes_zm/_weapons; +#include maps/mp/gametypes_zm/_globallogic_utils; +#include maps/mp/gametypes_zm/_globallogic_player; +#include maps/mp/_utility; + +callback_actordamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, boneindex ) +{ + if ( game[ "state" ] == "postgame" ) + { + return; + } + if ( self.aiteam == "spectator" ) + { + return; + } + if ( isDefined( eattacker ) && isplayer( eattacker ) && isDefined( eattacker.candocombat ) && !eattacker.candocombat ) + { + return; + } + self.idflags = idflags; + self.idflagstime = getTime(); + eattacker = maps/mp/gametypes_zm/_globallogic_player::figureoutattacker( eattacker ); + if ( !isDefined( vdir ) ) + { + idflags |= level.idflags_no_knockback; + } + friendly = 0; + if ( self.health == self.maxhealth || !isDefined( self.attackers ) ) + { + self.attackers = []; + self.attackerdata = []; + self.attackerdamage = []; + } + if ( maps/mp/gametypes_zm/_globallogic_utils::isheadshot( sweapon, shitloc, smeansofdeath, einflictor ) ) + { + smeansofdeath = "MOD_HEAD_SHOT"; + } + if ( level.onlyheadshots ) + { + if ( smeansofdeath == "MOD_PISTOL_BULLET" || smeansofdeath == "MOD_RIFLE_BULLET" ) + { + return; + } + else + { + if ( smeansofdeath == "MOD_HEAD_SHOT" ) + { + idamage = 150; + } + } + } + if ( sweapon == "none" && isDefined( einflictor ) ) + { + if ( isDefined( einflictor.targetname ) && einflictor.targetname == "explodable_barrel" ) + { + sweapon = "explodable_barrel_mp"; + } + else + { + if ( isDefined( einflictor.destructible_type ) && issubstr( einflictor.destructible_type, "vehicle_" ) ) + { + sweapon = "destructible_car_mp"; + } + } + } + if ( idflags & level.idflags_no_protection ) + { + if ( isplayer( eattacker ) ) + { + eattacker.pers[ "participation" ]++; + } + prevhealthratio = self.health / self.maxhealth; + if ( level.teambased && isplayer( eattacker ) && self != eattacker && self.aiteam == eattacker.pers[ "team" ] ) + { + if ( level.friendlyfire == 0 ) + { + return; + } + else if ( level.friendlyfire == 1 ) + { + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishactordamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, boneindex ); + } + else if ( level.friendlyfire == 2 ) + { + return; + } + else + { + if ( level.friendlyfire == 3 ) + { + idamage = int( idamage * 0,5 ); + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishactordamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, boneindex ); + } + } + friendly = 1; + } + else + { + if ( isDefined( eattacker ) && isDefined( self.script_owner ) && eattacker == self.script_owner && !level.hardcoremode ) + { + return; + } + if ( isDefined( eattacker ) && isDefined( self.script_owner ) && isDefined( eattacker.script_owner ) && eattacker.script_owner == self.script_owner ) + { + return; + } + if ( idamage < 1 ) + { + idamage = 1; + } + if ( isDefined( eattacker ) && isplayer( eattacker ) && isDefined( sweapon ) && !issubstr( smeansofdeath, "MOD_MELEE" ) ) + { + eattacker thread maps/mp/gametypes_zm/_weapons::checkhit( sweapon ); + } + if ( issubstr( smeansofdeath, "MOD_GRENADE" ) && isDefined( einflictor ) && isDefined( einflictor.iscooked ) ) + { + self.wascooked = getTime(); + } + else + { + self.wascooked = undefined; + } + if ( isDefined( eattacker ) ) + { + self.lastdamagewasfromenemy = eattacker != self; + } + self finishactordamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, boneindex ); + } + if ( isDefined( eattacker ) && eattacker != self ) + { + if ( sweapon != "artillery_mp" || !isDefined( einflictor ) && !isai( einflictor ) ) + { + if ( idamage > 0 ) + { + eattacker thread maps/mp/gametypes_zm/_damagefeedback::updatedamagefeedback( smeansofdeath, einflictor ); + } + } + } + } +/# + if ( getDvarInt( "g_debugDamage" ) ) + { + println( "actor:" + self getentitynumber() + " health:" + self.health + " attacker:" + eattacker.clientid + " inflictor is player:" + isplayer( einflictor ) + " damage:" + idamage + shitloc + ";" + boneindex + "\n" ); +#/ + } + if ( 1 ) + { + lpselfnum = self getentitynumber(); + lpselfteam = self.aiteam; + lpattackerteam = ""; + if ( isplayer( eattacker ) ) + { + lpattacknum = eattacker getentitynumber(); + lpattackguid = eattacker getguid(); + lpattackname = eattacker.name; + lpattackerteam = eattacker.pers[ "team" ]; + } + else + { + lpattacknum = -1; + lpattackguid = ""; + lpattackname = ""; + lpattackerteam = "world"; + } + logprint( "AD;" + lpselfnum + ";" + lpselfteam + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sweapon + ";" + idamage + ";" + smeansofdeath + ";" + shitloc + "\n" ); + } +} + +callback_actorkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime ) +{ + if ( game[ "state" ] == "postgame" ) + { + return; + } + if ( isai( attacker ) && isDefined( attacker.script_owner ) ) + { + if ( attacker.script_owner.team != self.aiteam ) + { + attacker = attacker.script_owner; + } + } + if ( attacker.classname == "script_vehicle" && isDefined( attacker.owner ) ) + { + attacker = attacker.owner; + } + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + if ( !level.teambased || self.aiteam != attacker.pers[ "team" ] ) + { + level.globalkillstreaksdestroyed++; + attacker addweaponstat( "dogs_mp", "destroyed", 1 ); + attacker maps/mp/_challenges::killeddog(); + } + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic_audio.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic_audio.gsc new file mode 100644 index 0000000..2618bd9 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic_audio.gsc @@ -0,0 +1,1034 @@ +#include maps/mp/_music; +#include maps/mp/gametypes_zm/_globallogic_audio; +#include maps/mp/gametypes_zm/_globallogic_utils; +#include maps/mp/_utility; + +init() +{ + game[ "music" ][ "defeat" ] = "mus_defeat"; + game[ "music" ][ "victory_spectator" ] = "mus_defeat"; + game[ "music" ][ "winning" ] = "mus_time_running_out_winning"; + game[ "music" ][ "losing" ] = "mus_time_running_out_losing"; + game[ "music" ][ "match_end" ] = "mus_match_end"; + game[ "music" ][ "victory_tie" ] = "mus_defeat"; + game[ "music" ][ "suspense" ] = []; + game[ "music" ][ "suspense" ][ game[ "music" ][ "suspense" ].size ] = "mus_suspense_01"; + game[ "music" ][ "suspense" ][ game[ "music" ][ "suspense" ].size ] = "mus_suspense_02"; + game[ "music" ][ "suspense" ][ game[ "music" ][ "suspense" ].size ] = "mus_suspense_03"; + game[ "music" ][ "suspense" ][ game[ "music" ][ "suspense" ].size ] = "mus_suspense_04"; + game[ "music" ][ "suspense" ][ game[ "music" ][ "suspense" ].size ] = "mus_suspense_05"; + game[ "music" ][ "suspense" ][ game[ "music" ][ "suspense" ].size ] = "mus_suspense_06"; + game[ "dialog" ][ "mission_success" ] = "mission_success"; + game[ "dialog" ][ "mission_failure" ] = "mission_fail"; + game[ "dialog" ][ "mission_draw" ] = "draw"; + game[ "dialog" ][ "round_success" ] = "encourage_win"; + game[ "dialog" ][ "round_failure" ] = "encourage_lost"; + game[ "dialog" ][ "round_draw" ] = "draw"; + game[ "dialog" ][ "timesup" ] = "timesup"; + game[ "dialog" ][ "winning" ] = "winning"; + game[ "dialog" ][ "losing" ] = "losing"; + game[ "dialog" ][ "min_draw" ] = "min_draw"; + game[ "dialog" ][ "lead_lost" ] = "lead_lost"; + game[ "dialog" ][ "lead_tied" ] = "tied"; + game[ "dialog" ][ "lead_taken" ] = "lead_taken"; + game[ "dialog" ][ "last_alive" ] = "lastalive"; + game[ "dialog" ][ "boost" ] = "generic_boost"; + if ( !isDefined( game[ "dialog" ][ "offense_obj" ] ) ) + { + game[ "dialog" ][ "offense_obj" ] = "generic_boost"; + } + if ( !isDefined( game[ "dialog" ][ "defense_obj" ] ) ) + { + game[ "dialog" ][ "defense_obj" ] = "generic_boost"; + } + game[ "dialog" ][ "hardcore" ] = "hardcore"; + game[ "dialog" ][ "oldschool" ] = "oldschool"; + game[ "dialog" ][ "highspeed" ] = "highspeed"; + game[ "dialog" ][ "tactical" ] = "tactical"; + game[ "dialog" ][ "challenge" ] = "challengecomplete"; + game[ "dialog" ][ "promotion" ] = "promotion"; + game[ "dialog" ][ "bomb_acquired" ] = "sd_bomb_taken"; + game[ "dialog" ][ "bomb_taken" ] = "sd_bomb_taken_taken"; + game[ "dialog" ][ "bomb_lost" ] = "sd_bomb_drop"; + game[ "dialog" ][ "bomb_defused" ] = "sd_bomb_defused"; + game[ "dialog" ][ "bomb_planted" ] = "sd_bomb_planted"; + game[ "dialog" ][ "obj_taken" ] = "securedobj"; + game[ "dialog" ][ "obj_lost" ] = "lostobj"; + game[ "dialog" ][ "obj_defend" ] = "defend_start"; + game[ "dialog" ][ "obj_destroy" ] = "destroy_start"; + game[ "dialog" ][ "obj_capture" ] = "capture_obj"; + game[ "dialog" ][ "objs_capture" ] = "capture_objs"; + game[ "dialog" ][ "hq_located" ] = "hq_located"; + game[ "dialog" ][ "hq_enemy_captured" ] = "hq_capture"; + game[ "dialog" ][ "hq_enemy_destroyed" ] = "hq_defend"; + game[ "dialog" ][ "hq_secured" ] = "hq_secured"; + game[ "dialog" ][ "hq_offline" ] = "hq_offline"; + game[ "dialog" ][ "hq_online" ] = "hq_online"; + game[ "dialog" ][ "koth_located" ] = "koth_located"; + game[ "dialog" ][ "koth_captured" ] = "koth_captured"; + game[ "dialog" ][ "koth_lost" ] = "koth_lost"; + game[ "dialog" ][ "koth_secured" ] = "koth_secured"; + game[ "dialog" ][ "koth_contested" ] = "koth_contest"; + game[ "dialog" ][ "koth_offline" ] = "koth_offline"; + game[ "dialog" ][ "koth_online" ] = "koth_online"; + game[ "dialog" ][ "move_to_new" ] = "new_positions"; + game[ "dialog" ][ "attack" ] = "attack"; + game[ "dialog" ][ "defend" ] = "defend"; + game[ "dialog" ][ "offense" ] = "offense"; + game[ "dialog" ][ "defense" ] = "defense"; + game[ "dialog" ][ "halftime" ] = "halftime"; + game[ "dialog" ][ "overtime" ] = "overtime"; + game[ "dialog" ][ "side_switch" ] = "switchingsides"; + game[ "dialog" ][ "flag_taken" ] = "ourflag"; + game[ "dialog" ][ "flag_dropped" ] = "ourflag_drop"; + game[ "dialog" ][ "flag_returned" ] = "ourflag_return"; + game[ "dialog" ][ "flag_captured" ] = "ourflag_capt"; + game[ "dialog" ][ "enemy_flag_taken" ] = "enemyflag"; + game[ "dialog" ][ "enemy_flag_dropped" ] = "enemyflag_drop"; + game[ "dialog" ][ "enemy_flag_returned" ] = "enemyflag_return"; + game[ "dialog" ][ "enemy_flag_captured" ] = "enemyflag_capt"; + game[ "dialog" ][ "securing_a" ] = "dom_securing_a"; + game[ "dialog" ][ "securing_b" ] = "dom_securing_b"; + game[ "dialog" ][ "securing_c" ] = "dom_securing_c"; + game[ "dialog" ][ "securing_d" ] = "dom_securing_d"; + game[ "dialog" ][ "securing_e" ] = "dom_securing_e"; + game[ "dialog" ][ "securing_f" ] = "dom_securing_f"; + game[ "dialog" ][ "secured_a" ] = "dom_secured_a"; + game[ "dialog" ][ "secured_b" ] = "dom_secured_b"; + game[ "dialog" ][ "secured_c" ] = "dom_secured_c"; + game[ "dialog" ][ "secured_d" ] = "dom_secured_d"; + game[ "dialog" ][ "secured_e" ] = "dom_secured_e"; + game[ "dialog" ][ "secured_f" ] = "dom_secured_f"; + game[ "dialog" ][ "losing_a" ] = "dom_losing_a"; + game[ "dialog" ][ "losing_b" ] = "dom_losing_b"; + game[ "dialog" ][ "losing_c" ] = "dom_losing_c"; + game[ "dialog" ][ "losing_d" ] = "dom_losing_d"; + game[ "dialog" ][ "losing_e" ] = "dom_losing_e"; + game[ "dialog" ][ "losing_f" ] = "dom_losing_f"; + game[ "dialog" ][ "lost_a" ] = "dom_lost_a"; + game[ "dialog" ][ "lost_b" ] = "dom_lost_b"; + game[ "dialog" ][ "lost_c" ] = "dom_lost_c"; + game[ "dialog" ][ "lost_d" ] = "dom_lost_d"; + game[ "dialog" ][ "lost_e" ] = "dom_lost_e"; + game[ "dialog" ][ "lost_f" ] = "dom_lost_f"; + game[ "dialog" ][ "secure_flag" ] = "secure_flag"; + game[ "dialog" ][ "securing_flag" ] = "securing_flag"; + game[ "dialog" ][ "losing_flag" ] = "losing_flag"; + game[ "dialog" ][ "lost_flag" ] = "lost_flag"; + game[ "dialog" ][ "oneflag_enemy" ] = "oneflag_enemy"; + game[ "dialog" ][ "oneflag_friendly" ] = "oneflag_friendly"; + game[ "dialog" ][ "lost_all" ] = "dom_lock_theytake"; + game[ "dialog" ][ "secure_all" ] = "dom_lock_wetake"; + game[ "dialog" ][ "squad_move" ] = "squad_move"; + game[ "dialog" ][ "squad_30sec" ] = "squad_30sec"; + game[ "dialog" ][ "squad_winning" ] = "squad_onemin_vic"; + game[ "dialog" ][ "squad_losing" ] = "squad_onemin_loss"; + game[ "dialog" ][ "squad_down" ] = "squad_down"; + game[ "dialog" ][ "squad_bomb" ] = "squad_bomb"; + game[ "dialog" ][ "squad_plant" ] = "squad_plant"; + game[ "dialog" ][ "squad_take" ] = "squad_takeobj"; + game[ "dialog" ][ "kicked" ] = "player_kicked"; + game[ "dialog" ][ "sentry_destroyed" ] = "dest_sentry"; + game[ "dialog" ][ "sentry_hacked" ] = "kls_turret_hacked"; + game[ "dialog" ][ "microwave_destroyed" ] = "dest_microwave"; + game[ "dialog" ][ "microwave_hacked" ] = "kls_microwave_hacked"; + game[ "dialog" ][ "sam_destroyed" ] = "dest_sam"; + game[ "dialog" ][ "tact_destroyed" ] = "dest_tact"; + game[ "dialog" ][ "equipment_destroyed" ] = "dest_equip"; + game[ "dialog" ][ "hacked_equip" ] = "hacked_equip"; + game[ "dialog" ][ "uav_destroyed" ] = "kls_u2_destroyed"; + game[ "dialog" ][ "cuav_destroyed" ] = "kls_cu2_destroyed"; + level.dialoggroups = []; + level thread post_match_snapshot_watcher(); +} + +registerdialoggroup( group, skipifcurrentlyplayinggroup ) +{ + if ( !isDefined( level.dialoggroups ) ) + { + level.dialoggroups = []; + } + else + { + if ( isDefined( level.dialoggroup[ group ] ) ) + { + error( "registerDialogGroup: Dialog group " + group + " already registered." ); + return; + } + } + level.dialoggroup[ group ] = spawnstruct(); + level.dialoggroup[ group ].group = group; + level.dialoggroup[ group ].skipifcurrentlyplayinggroup = skipifcurrentlyplayinggroup; + level.dialoggroup[ group ].currentcount = 0; +} + +sndstartmusicsystem() +{ + self endon( "disconnect" ); + if ( game[ "state" ] == "postgame" ) + { + return; + } + if ( game[ "state" ] == "pregame" ) + { +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - music state is undefined Waiting 15 seconds to set music state" ); +#/ + } + wait 30; + if ( !isDefined( level.nextmusicstate ) ) + { + self.pers[ "music" ].currentstate = "UNDERSCORE"; + self thread suspensemusic(); + } + } + if ( !isDefined( level.nextmusicstate ) ) + { +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - music state is undefined Waiting 15 seconds to set music state" ); +#/ + } + self.pers[ "music" ].currentstate = "UNDERSCORE"; + self thread suspensemusic(); + } +} + +suspensemusicforplayer() +{ + self endon( "disconnect" ); + self thread set_music_on_player( "UNDERSCORE", 0 ); +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Setting Music State Random Underscore " + self.pers[ "music" ].returnstate + " On player " + self getentitynumber() ); +#/ + } +} + +suspensemusic( random ) +{ + level endon( "game_ended" ); + level endon( "match_ending_soon" ); + self endon( "disconnect" ); +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Starting random underscore" ); +#/ + } + while ( 1 ) + { + wait randomintrange( 25, 60 ); +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Checking for random underscore" ); +#/ + } + if ( !isDefined( self.pers[ "music" ].inque ) ) + { + self.pers[ "music" ].inque = 0; + } + while ( self.pers[ "music" ].inque ) + { +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Inque no random underscore" ); +#/ + } + } + if ( !isDefined( self.pers[ "music" ].currentstate ) ) + { + self.pers[ "music" ].currentstate = "SILENT"; + } + if ( randomint( 100 ) < self.underscorechance && self.pers[ "music" ].currentstate != "ACTION" && self.pers[ "music" ].currentstate != "TIME_OUT" ) + { + self thread suspensemusicforplayer(); + self.underscorechance -= 20; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Starting random underscore" ); +#/ + } + } + } +} + +leaderdialogforotherteams( dialog, skip_team, squad_dialog ) +{ + _a339 = level.teams; + _k339 = getFirstArrayKey( _a339 ); + while ( isDefined( _k339 ) ) + { + team = _a339[ _k339 ]; + if ( team != skip_team ) + { + leaderdialog( dialog, team, undefined, undefined, squad_dialog ); + } + _k339 = getNextArrayKey( _a339, _k339 ); + } +} + +announceroundwinner( winner, delay ) +{ + if ( delay > 0 ) + { + wait delay; + } + if ( !isDefined( winner ) || isplayer( winner ) ) + { + return; + } + if ( isDefined( level.teams[ winner ] ) ) + { + leaderdialog( "round_success", winner ); + leaderdialogforotherteams( "round_failure", winner ); + } + else + { + _a365 = level.teams; + _k365 = getFirstArrayKey( _a365 ); + while ( isDefined( _k365 ) ) + { + team = _a365[ _k365 ]; + thread playsoundonplayers( "mus_round_draw" + "_" + level.teampostfix[ team ] ); + _k365 = getNextArrayKey( _a365, _k365 ); + } + leaderdialog( "round_draw" ); + } +} + +announcegamewinner( winner, delay ) +{ + if ( delay > 0 ) + { + wait delay; + } + if ( !isDefined( winner ) || isplayer( winner ) ) + { + return; + } + if ( isDefined( level.teams[ winner ] ) ) + { + leaderdialog( "mission_success", winner ); + leaderdialogforotherteams( "mission_failure", winner ); + } + else + { + leaderdialog( "mission_draw" ); + } +} + +doflameaudio() +{ + self endon( "disconnect" ); + waittillframeend; + if ( !isDefined( self.lastflamehurtaudio ) ) + { + self.lastflamehurtaudio = 0; + } + currenttime = getTime(); + if ( ( self.lastflamehurtaudio + level.fire_audio_repeat_duration + randomint( level.fire_audio_random_max_duration ) ) < currenttime ) + { + self playlocalsound( "vox_pain_small" ); + self.lastflamehurtaudio = currenttime; + } +} + +leaderdialog( dialog, team, group, excludelist, squaddialog ) +{ +/# + assert( isDefined( level.players ) ); +#/ + if ( level.splitscreen ) + { + return; + } + if ( level.wagermatch ) + { + return; + } + if ( !isDefined( team ) ) + { + dialogs = []; + _a425 = level.teams; + _k425 = getFirstArrayKey( _a425 ); + while ( isDefined( _k425 ) ) + { + team = _a425[ _k425 ]; + dialogs[ team ] = dialog; + _k425 = getNextArrayKey( _a425, _k425 ); + } + leaderdialogallteams( dialogs, group, excludelist ); + return; + } + if ( level.splitscreen ) + { + if ( level.players.size ) + { + level.players[ 0 ] leaderdialogonplayer( dialog, group ); + } + return; + } + if ( isDefined( excludelist ) ) + { + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team && !maps/mp/gametypes_zm/_globallogic_utils::isexcluded( player, excludelist ) ) + { + player leaderdialogonplayer( dialog, group ); + } + i++; + } + } + else i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player leaderdialogonplayer( dialog, group ); + } + i++; + } +} + +leaderdialogallteams( dialogs, group, excludelist ) +{ +/# + assert( isDefined( level.players ) ); +#/ + if ( level.splitscreen ) + { + return; + } + if ( level.splitscreen ) + { + if ( level.players.size ) + { + level.players[ 0 ] leaderdialogonplayer( dialogs[ level.players[ 0 ].team ], group ); + } + return; + } + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + team = player.pers[ "team" ]; + if ( !isDefined( team ) ) + { + i++; + continue; + } + else if ( !isDefined( dialogs[ team ] ) ) + { + i++; + continue; + } + else if ( isDefined( excludelist ) && maps/mp/gametypes_zm/_globallogic_utils::isexcluded( player, excludelist ) ) + { + i++; + continue; + } + else + { + player leaderdialogonplayer( dialogs[ team ], group ); + } + i++; + } +} + +flushdialog() +{ + _a495 = level.players; + _k495 = getFirstArrayKey( _a495 ); + while ( isDefined( _k495 ) ) + { + player = _a495[ _k495 ]; + player flushdialogonplayer(); + _k495 = getNextArrayKey( _a495, _k495 ); + } +} + +flushdialogonplayer() +{ + self.leaderdialoggroups = []; + self.leaderdialogqueue = []; + self.leaderdialogactive = 0; + self.currentleaderdialoggroup = ""; +} + +flushgroupdialog( group ) +{ + _a512 = level.players; + _k512 = getFirstArrayKey( _a512 ); + while ( isDefined( _k512 ) ) + { + player = _a512[ _k512 ]; + player flushgroupdialogonplayer( group ); + _k512 = getNextArrayKey( _a512, _k512 ); + } +} + +flushgroupdialogonplayer( group ) +{ + _a522 = self.leaderdialogqueue; + key = getFirstArrayKey( _a522 ); + while ( isDefined( key ) ) + { + dialog = _a522[ key ]; + if ( dialog == group ) + { + } + key = getNextArrayKey( _a522, key ); + } +} + +addgroupdialogtoplayer( dialog, group ) +{ + if ( !isDefined( level.dialoggroup[ group ] ) ) + { + error( "leaderDialogOnPlayer: Dialog group " + group + " is not registered" ); + return 0; + } + addtoqueue = 0; + if ( !isDefined( self.leaderdialoggroups[ group ] ) ) + { + addtoqueue = 1; + } + if ( !level.dialoggroup[ group ].skipifcurrentlyplayinggroup ) + { + if ( self.currentleaderdialog == dialog && ( self.currentleaderdialogtime + 2000 ) > getTime() ) + { + _a552 = self.leaderdialogqueue; + key = getFirstArrayKey( _a552 ); + while ( isDefined( key ) ) + { + leader_dialog = _a552[ key ]; + if ( leader_dialog == group ) + { + i = key + 1; + while ( i < self.leaderdialogqueue.size ) + { + self.leaderdialogqueue[ i - 1 ] = self.leaderdialogqueue[ i ]; + i++; + } + break; + } + else + { + key = getNextArrayKey( _a552, key ); + } + } + return 0; + } + } + else + { + if ( self.currentleaderdialoggroup == group ) + { + return 0; + } + } + self.leaderdialoggroups[ group ] = dialog; + return addtoqueue; +} + +testdialogqueue( group ) +{ +/# + count = 0; + _a585 = self.leaderdialogqueue; + _k585 = getFirstArrayKey( _a585 ); + while ( isDefined( _k585 ) ) + { + temp = _a585[ _k585 ]; + if ( temp == group ) + { + count++; + } + _k585 = getNextArrayKey( _a585, _k585 ); + } + if ( count > 1 ) + { + shit = 0; +#/ + } +} + +leaderdialogonplayer( dialog, group ) +{ + team = self.pers[ "team" ]; + if ( level.splitscreen ) + { + return; + } + if ( !isDefined( team ) ) + { + return; + } + if ( !isDefined( level.teams[ team ] ) ) + { + return; + } + if ( isDefined( group ) ) + { + if ( !addgroupdialogtoplayer( dialog, group ) ) + { + self testdialogqueue( group ); + return; + } + dialog = group; + } + if ( !self.leaderdialogactive ) + { + self thread playleaderdialogonplayer( dialog ); + } + else + { + self.leaderdialogqueue[ self.leaderdialogqueue.size ] = dialog; + } +} + +waitforsound( sound, extratime ) +{ + if ( !isDefined( extratime ) ) + { + extratime = 0,1; + } + time = soundgetplaybacktime( sound ); + if ( time < 0 ) + { + wait ( 3 + extratime ); + } + else + { + wait ( ( time * 0,001 ) + extratime ); + } +} + +playleaderdialogonplayer( dialog ) +{ + if ( isDefined( level.allowannouncer ) && !level.allowannouncer ) + { + return; + } + team = self.pers[ "team" ]; + self endon( "disconnect" ); + self.leaderdialogactive = 1; + if ( isDefined( self.leaderdialoggroups[ dialog ] ) ) + { + group = dialog; + dialog = self.leaderdialoggroups[ group ]; + self.currentleaderdialoggroup = group; + self testdialogqueue( group ); + } + if ( level.wagermatch || !isDefined( game[ "voice" ] ) ) + { + faction = "vox_wm_"; + } + else + { + faction = game[ "voice" ][ team ]; + } + sound_name = faction + game[ "dialog" ][ dialog ]; + if ( level.allowannouncer ) + { + self playlocalsound( sound_name ); + self.currentleaderdialog = dialog; + self.currentleaderdialogtime = getTime(); + } + waitforsound( sound_name ); + self.leaderdialogactive = 0; + self.currentleaderdialoggroup = ""; + self.currentleaderdialog = ""; + if ( self.leaderdialogqueue.size > 0 ) + { + nextdialog = self.leaderdialogqueue[ 0 ]; + i = 1; + while ( i < self.leaderdialogqueue.size ) + { + self.leaderdialogqueue[ i - 1 ] = self.leaderdialogqueue[ i ]; + i++; + } + if ( isDefined( self.leaderdialoggroups[ dialog ] ) ) + { + self testdialogqueue( dialog ); + } + self thread playleaderdialogonplayer( nextdialog ); + } +} + +isteamwinning( checkteam ) +{ + score = game[ "teamScores" ][ checkteam ]; + _a702 = level.teams; + _k702 = getFirstArrayKey( _a702 ); + while ( isDefined( _k702 ) ) + { + team = _a702[ _k702 ]; + if ( team != checkteam ) + { + if ( game[ "teamScores" ][ team ] >= score ) + { + return 0; + } + } + _k702 = getNextArrayKey( _a702, _k702 ); + } + return 1; +} + +announceteamiswinning() +{ + _a716 = level.teams; + _k716 = getFirstArrayKey( _a716 ); + while ( isDefined( _k716 ) ) + { + team = _a716[ _k716 ]; + if ( isteamwinning( team ) ) + { + leaderdialog( "winning", team, undefined, undefined, "squad_winning" ); + leaderdialogforotherteams( "losing", team, "squad_losing" ); + return 1; + } + _k716 = getNextArrayKey( _a716, _k716 ); + } + return 0; +} + +musiccontroller() +{ + level endon( "game_ended" ); + level thread musictimesout(); + level waittill( "match_ending_soon" ); + if ( islastround() || isoneround() ) + { + while ( !level.splitscreen ) + { + if ( level.teambased ) + { + if ( !announceteamiswinning() ) + { + leaderdialog( "min_draw" ); + } + } + level waittill( "match_ending_very_soon" ); + _a751 = level.teams; + _k751 = getFirstArrayKey( _a751 ); + while ( isDefined( _k751 ) ) + { + team = _a751[ _k751 ]; + leaderdialog( "timesup", team, undefined, undefined, "squad_30sec" ); + _k751 = getNextArrayKey( _a751, _k751 ); + } + } + } + else level waittill( "match_ending_vox" ); + leaderdialog( "timesup" ); +} + +musictimesout() +{ + level endon( "game_ended" ); + level waittill( "match_ending_very_soon" ); + thread maps/mp/gametypes_zm/_globallogic_audio::set_music_on_team( "TIME_OUT", "both", 1, 0 ); +} + +actionmusicset() +{ + level endon( "game_ended" ); + level.playingactionmusic = 1; + wait 45; + level.playingactionmusic = 0; +} + +play_2d_on_team( alias, team ) +{ +/# + assert( isDefined( level.players ) ); +#/ + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player playlocalsound( alias ); + } + i++; + } +} + +set_music_on_team( state, team, save_state, return_state, wait_time ) +{ + if ( sessionmodeiszombiesgame() ) + { + return; + } +/# + assert( isDefined( level.players ) ); +#/ + if ( !isDefined( team ) ) + { + team = "both"; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - team undefined: Setting to both" ); +#/ + } + } + if ( !isDefined( save_state ) ) + { + save_sate = 0; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - save_sate undefined: Setting to false" ); +#/ + } + } + if ( !isDefined( return_state ) ) + { + return_state = 0; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Music System - return_state undefined: Setting to false" ); +#/ + } + } + if ( !isDefined( wait_time ) ) + { + wait_time = 0; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - wait_time undefined: Setting to 0" ); +#/ + } + } + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( team == "both" ) + { + player thread set_music_on_player( state, save_state, return_state, wait_time ); + i++; + continue; + } + else + { + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player thread set_music_on_player( state, save_state, return_state, wait_time ); +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Setting Music State " + state + " On player " + player getentitynumber() ); +#/ + } + } + } + i++; + } +} + +set_music_on_player( state, save_state, return_state, wait_time ) +{ + self endon( "disconnect" ); + if ( sessionmodeiszombiesgame() ) + { + return; + } +/# + assert( isplayer( self ) ); +#/ + if ( !isDefined( save_state ) ) + { + save_state = 0; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Music System - save_sate undefined: Setting to false" ); +#/ + } + } + if ( !isDefined( return_state ) ) + { + return_state = 0; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Music System - return_state undefined: Setting to false" ); +#/ + } + } + if ( !isDefined( wait_time ) ) + { + wait_time = 0; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - wait_time undefined: Setting to 0" ); +#/ + } + } + if ( !isDefined( state ) ) + { + state = "UNDERSCORE"; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - state undefined: Setting to UNDERSCORE" ); +#/ + } + } + maps/mp/_music::setmusicstate( state, self ); + if ( isDefined( self.pers[ "music" ].currentstate ) && save_state ) + { + self.pers[ "music" ].returnstate = state; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Saving Music State " + self.pers[ "music" ].returnstate + " On " + self getentitynumber() ); +#/ + } + } + self.pers[ "music" ].previousstate = self.pers[ "music" ].currentstate; + self.pers[ "music" ].currentstate = state; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Setting Music State " + state + " On player " + self getentitynumber() ); +#/ + } + if ( isDefined( self.pers[ "music" ].returnstate ) && return_state ) + { +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Starting Return State " + self.pers[ "music" ].returnstate + " On " + self getentitynumber() ); +#/ + } + self set_next_music_state( self.pers[ "music" ].returnstate, wait_time ); + } +} + +return_music_state_player( wait_time ) +{ + if ( !isDefined( wait_time ) ) + { + wait_time = 0; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - wait_time undefined: Setting to 0" ); +#/ + } + } + self set_next_music_state( self.pers[ "music" ].returnstate, wait_time ); +} + +return_music_state_team( team, wait_time ) +{ + if ( !isDefined( wait_time ) ) + { + wait_time = 0; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - wait_time undefined: Setting to 0" ); +#/ + } + } + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( team == "both" ) + { + player thread set_next_music_state( self.pers[ "music" ].returnstate, wait_time ); + i++; + continue; + } + else + { + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team ) + { + player thread set_next_music_state( self.pers[ "music" ].returnstate, wait_time ); +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Setting Music State " + self.pers[ "music" ].returnstate + " On player " + player getentitynumber() ); +#/ + } + } + } + i++; + } +} + +set_next_music_state( nextstate, wait_time ) +{ + self endon( "disconnect" ); + self.pers[ "music" ].nextstate = nextstate; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - Setting next Music State " + self.pers[ "music" ].nextstate + " On " + self getentitynumber() ); +#/ + } + if ( !isDefined( self.pers[ "music" ].inque ) ) + { + self.pers[ "music" ].inque = 0; + } + if ( self.pers[ "music" ].inque ) + { + return; +/# + println( "Music System - Music state in que" ); +#/ + } + else + { + self.pers[ "music" ].inque = 1; + if ( wait_time ) + { + wait wait_time; + } + self set_music_on_player( self.pers[ "music" ].nextstate, 0 ); + self.pers[ "music" ].inque = 0; + } +} + +getroundswitchdialog( switchtype ) +{ + switch( switchtype ) + { + case "halftime": + return "halftime"; + case "overtime": + return "overtime"; + default: + return "side_switch"; + } +} + +post_match_snapshot_watcher() +{ + level waittill( "game_ended" ); + level clientnotify( "pm" ); + level waittill( "sfade" ); + level clientnotify( "pmf" ); +} diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic_defaults.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic_defaults.gsc new file mode 100644 index 0000000..059642d --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic_defaults.gsc @@ -0,0 +1,230 @@ +#include maps/mp/gametypes_zm/_spawnlogic; +#include maps/mp/gametypes_zm/_globallogic_audio; +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/gametypes_zm/_globallogic; +#include maps/mp/gametypes_zm/_globallogic_utils; +#include maps/mp/_utility; +#include common_scripts/utility; + +getwinningteamfromloser( losing_team ) +{ + if ( level.multiteam ) + { + return "tie"; + } + else + { + if ( losing_team == "axis" ) + { + return "allies"; + } + } + return "axis"; +} + +default_onforfeit( team ) +{ + level.gameforfeited = 1; + level notify( "forfeit in progress" ); + level endon( "forfeit in progress" ); + level endon( "abort forfeit" ); + forfeit_delay = 20; + announcement( game[ "strings" ][ "opponent_forfeiting_in" ], forfeit_delay, 0 ); + wait 10; + announcement( game[ "strings" ][ "opponent_forfeiting_in" ], 10, 0 ); + wait 10; + endreason = &""; + if ( !isDefined( team ) ) + { + setdvar( "ui_text_endreason", game[ "strings" ][ "players_forfeited" ] ); + endreason = game[ "strings" ][ "players_forfeited" ]; + winner = level.players[ 0 ]; + } + else if ( isDefined( level.teams[ team ] ) ) + { + endreason = game[ "strings" ][ team + "_forfeited" ]; + setdvar( "ui_text_endreason", endreason ); + winner = getwinningteamfromloser( team ); + } + else + { +/# + assert( isDefined( team ), "Forfeited team is not defined" ); +#/ +/# + assert( 0, "Forfeited team " + team + " is not allies or axis" ); +#/ + winner = "tie"; + } + level.forcedend = 1; + if ( isplayer( winner ) ) + { + logstring( "forfeit, win: " + winner getxuid() + "(" + winner.name + ")" ); + } + else + { + maps/mp/gametypes_zm/_globallogic_utils::logteamwinstring( "forfeit", winner ); + } + thread maps/mp/gametypes_zm/_globallogic::endgame( winner, endreason ); +} + +default_ondeadevent( team ) +{ + if ( isDefined( level.teams[ team ] ) ) + { + eliminatedstring = game[ "strings" ][ team + "_eliminated" ]; + iprintln( eliminatedstring ); + makedvarserverinfo( "ui_text_endreason", eliminatedstring ); + setdvar( "ui_text_endreason", eliminatedstring ); + winner = getwinningteamfromloser( team ); + maps/mp/gametypes_zm/_globallogic_utils::logteamwinstring( "team eliminated", winner ); + thread maps/mp/gametypes_zm/_globallogic::endgame( winner, eliminatedstring ); + } + else makedvarserverinfo( "ui_text_endreason", game[ "strings" ][ "tie" ] ); + setdvar( "ui_text_endreason", game[ "strings" ][ "tie" ] ); + maps/mp/gametypes_zm/_globallogic_utils::logteamwinstring( "tie" ); + if ( level.teambased ) + { + thread maps/mp/gametypes_zm/_globallogic::endgame( "tie", game[ "strings" ][ "tie" ] ); + } + else + { + thread maps/mp/gametypes_zm/_globallogic::endgame( undefined, game[ "strings" ][ "tie" ] ); + } +} + +default_onalivecountchange( team ) +{ +} + +default_onroundendgame( winner ) +{ + return winner; +} + +default_ononeleftevent( team ) +{ + if ( !level.teambased ) + { + winner = maps/mp/gametypes_zm/_globallogic_score::gethighestscoringplayer(); + if ( isDefined( winner ) ) + { + logstring( "last one alive, win: " + winner.name ); + } + else + { + logstring( "last one alive, win: unknown" ); + } + thread maps/mp/gametypes_zm/_globallogic::endgame( winner, &"MP_ENEMIES_ELIMINATED" ); + } + else + { + index = 0; + while ( index < level.players.size ) + { + player = level.players[ index ]; + if ( !isalive( player ) ) + { + index++; + continue; + } + else if ( !isDefined( player.pers[ "team" ] ) || player.pers[ "team" ] != team ) + { + index++; + continue; + } + else + { + player maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "sudden_death" ); + } + index++; + } + } +} + +default_ontimelimit() +{ + winner = undefined; + if ( level.teambased ) + { + winner = maps/mp/gametypes_zm/_globallogic::determineteamwinnerbygamestat( "teamScores" ); + maps/mp/gametypes_zm/_globallogic_utils::logteamwinstring( "time limit", winner ); + } + else winner = maps/mp/gametypes_zm/_globallogic_score::gethighestscoringplayer(); + if ( isDefined( winner ) ) + { + logstring( "time limit, win: " + winner.name ); + } + else + { + logstring( "time limit, tie" ); + } + makedvarserverinfo( "ui_text_endreason", game[ "strings" ][ "time_limit_reached" ] ); + setdvar( "ui_text_endreason", game[ "strings" ][ "time_limit_reached" ] ); + thread maps/mp/gametypes_zm/_globallogic::endgame( winner, game[ "strings" ][ "time_limit_reached" ] ); +} + +default_onscorelimit() +{ + if ( !level.endgameonscorelimit ) + { + return 0; + } + winner = undefined; + if ( level.teambased ) + { + winner = maps/mp/gametypes_zm/_globallogic::determineteamwinnerbygamestat( "teamScores" ); + maps/mp/gametypes_zm/_globallogic_utils::logteamwinstring( "scorelimit", winner ); + } + else winner = maps/mp/gametypes_zm/_globallogic_score::gethighestscoringplayer(); + if ( isDefined( winner ) ) + { + logstring( "scorelimit, win: " + winner.name ); + } + else + { + logstring( "scorelimit, tie" ); + } + makedvarserverinfo( "ui_text_endreason", game[ "strings" ][ "score_limit_reached" ] ); + setdvar( "ui_text_endreason", game[ "strings" ][ "score_limit_reached" ] ); + thread maps/mp/gametypes_zm/_globallogic::endgame( winner, game[ "strings" ][ "score_limit_reached" ] ); + return 1; +} + +default_onspawnspectator( origin, angles ) +{ + if ( isDefined( origin ) && isDefined( angles ) ) + { + self spawn( origin, angles ); + return; + } + spawnpointname = "mp_global_intermission"; + spawnpoints = getentarray( spawnpointname, "classname" ); +/# + assert( spawnpoints.size, "There are no mp_global_intermission spawn points in the map. There must be at least one." ); +#/ + spawnpoint = maps/mp/gametypes_zm/_spawnlogic::getspawnpoint_random( spawnpoints ); + self spawn( spawnpoint.origin, spawnpoint.angles ); +} + +default_onspawnintermission() +{ + spawnpointname = "mp_global_intermission"; + spawnpoints = getentarray( spawnpointname, "classname" ); + spawnpoint = spawnpoints[ 0 ]; + if ( isDefined( spawnpoint ) ) + { + self spawn( spawnpoint.origin, spawnpoint.angles ); + } + else + { +/# + maps/mp/_utility::error( "NO " + spawnpointname + " SPAWNPOINTS IN MAP" ); +#/ + } +} + +default_gettimelimit() +{ + return clamp( getgametypesetting( "timeLimit" ), level.timelimitmin, level.timelimitmax ); +} diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic_player.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic_player.gsc new file mode 100644 index 0000000..2de5b99 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic_player.gsc @@ -0,0 +1,2238 @@ +#include maps/mp/gametypes_zm/_globallogic_audio; +#include maps/mp/gametypes_zm/_tweakables; +#include maps/mp/_challenges; +#include maps/mp/gametypes_zm/_spawnlogic; +#include maps/mp/gametypes_zm/_weapons; +#include maps/mp/_demo; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/gametypes_zm/_hud_message; +#include maps/mp/gametypes_zm/_spawning; +#include maps/mp/gametypes_zm/_globallogic_utils; +#include maps/mp/gametypes_zm/_spectating; +#include maps/mp/gametypes_zm/_globallogic_spawn; +#include maps/mp/gametypes_zm/_globallogic_ui; +#include maps/mp/gametypes_zm/_hostmigration; +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/gametypes_zm/_globallogic; +#include common_scripts/utility; +#include maps/mp/_utility; + +freezeplayerforroundend() +{ + self clearlowermessage(); + self closemenu(); + self closeingamemenu(); + self freeze_player_controls( 1 ); + if ( !sessionmodeiszombiesgame() ) + { + currentweapon = self getcurrentweapon(); + } +} + +callback_playerconnect() +{ + thread notifyconnecting(); + self.statusicon = "hud_status_connecting"; + self waittill( "begin" ); + if ( isDefined( level.reset_clientdvars ) ) + { + self [[ level.reset_clientdvars ]](); + } + waittillframeend; + self.statusicon = ""; + self.guid = self getguid(); + profilelog_begintiming( 4, "ship" ); + level notify( "connected" ); + if ( self ishost() ) + { + self thread maps/mp/gametypes_zm/_globallogic::listenforgameend(); + } + if ( !level.splitscreen && !isDefined( self.pers[ "score" ] ) ) + { + iprintln( &"MP_CONNECTED", self ); + } + if ( !isDefined( self.pers[ "score" ] ) ) + { + self thread maps/mp/zombies/_zm_stats::adjustrecentstats(); + } + if ( gamemodeismode( level.gamemode_public_match ) && !isDefined( self.pers[ "matchesPlayedStatsTracked" ] ) ) + { + gamemode = maps/mp/gametypes_zm/_globallogic::getcurrentgamemode(); + self maps/mp/gametypes_zm/_globallogic::incrementmatchcompletionstat( gamemode, "played", "started" ); + if ( !isDefined( self.pers[ "matchesHostedStatsTracked" ] ) && self islocaltohost() ) + { + self maps/mp/gametypes_zm/_globallogic::incrementmatchcompletionstat( gamemode, "hosted", "started" ); + self.pers[ "matchesHostedStatsTracked" ] = 1; + } + self.pers[ "matchesPlayedStatsTracked" ] = 1; + self thread maps/mp/zombies/_zm_stats::uploadstatssoon(); + } + lpselfnum = self getentitynumber(); + lpguid = self getguid(); + logprint( "J;" + lpguid + ";" + lpselfnum + ";" + self.name + "\n" ); + bbprint( "mpjoins", "name %s client %s", self.name, lpselfnum ); + if ( !sessionmodeiszombiesgame() ) + { + self setclientuivisibilityflag( "hud_visible", 1 ); + } + if ( level.forceradar == 1 ) + { + self.pers[ "hasRadar" ] = 1; + self.hasspyplane = 1; + level.activeuavs[ self getentitynumber() ] = 1; + } + if ( level.forceradar == 2 ) + { + self setclientuivisibilityflag( "g_compassShowEnemies", level.forceradar ); + } + else + { + self setclientuivisibilityflag( "g_compassShowEnemies", 0 ); + } + self setclientplayersprinttime( level.playersprinttime ); + self setclientnumlives( level.numlives ); + makedvarserverinfo( "cg_drawTalk", 1 ); + if ( level.hardcoremode ) + { + self setclientdrawtalk( 3 ); + } + if ( sessionmodeiszombiesgame() ) + { + self [[ level.player_stats_init ]](); + } + else + { + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "score" ); + if ( level.resetplayerscoreeveryround ) + { + self.pers[ "score" ] = 0; + } + self.score = self.pers[ "score" ]; + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "momentum", 0 ); + self.momentum = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "momentum" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "suicides" ); + self.suicides = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "suicides" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "headshots" ); + self.headshots = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "headshots" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "challenges" ); + self.challenges = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "challenges" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "kills" ); + self.kills = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "kills" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "deaths" ); + self.deaths = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "deaths" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "assists" ); + self.assists = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "assists" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "defends", 0 ); + self.defends = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "defends" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "offends", 0 ); + self.offends = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "offends" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "plants", 0 ); + self.plants = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "plants" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "defuses", 0 ); + self.defuses = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "defuses" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "returns", 0 ); + self.returns = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "returns" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "captures", 0 ); + self.captures = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "captures" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "destructions", 0 ); + self.destructions = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "destructions" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "backstabs", 0 ); + self.backstabs = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "backstabs" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "longshots", 0 ); + self.longshots = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "longshots" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "survived", 0 ); + self.survived = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "survived" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "stabs", 0 ); + self.stabs = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "stabs" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "tomahawks", 0 ); + self.tomahawks = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "tomahawks" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "humiliated", 0 ); + self.humiliated = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "humiliated" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "x2score", 0 ); + self.x2score = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "x2score" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "agrkills", 0 ); + self.x2score = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "agrkills" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "hacks", 0 ); + self.x2score = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "hacks" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "sessionbans", 0 ); + self.sessionbans = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "sessionbans" ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "gametypeban", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "time_played_total", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "time_played_alive", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "teamkills", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "teamkills_nostats", 0 ); + self.teamkillpunish = 0; + if ( level.minimumallowedteamkills >= 0 && self.pers[ "teamkills_nostats" ] > level.minimumallowedteamkills ) + { + self thread reduceteamkillsovertime(); + } + } + if ( getDvar( #"F7B30924" ) == "1" ) + { + level waittill( "eternity" ); + } + self.killedplayerscurrent = []; + if ( !isDefined( self.pers[ "best_kill_streak" ] ) ) + { + self.pers[ "killed_players" ] = []; + self.pers[ "killed_by" ] = []; + self.pers[ "nemesis_tracking" ] = []; + self.pers[ "artillery_kills" ] = 0; + self.pers[ "dog_kills" ] = 0; + self.pers[ "nemesis_name" ] = ""; + self.pers[ "nemesis_rank" ] = 0; + self.pers[ "nemesis_rankIcon" ] = 0; + self.pers[ "nemesis_xp" ] = 0; + self.pers[ "nemesis_xuid" ] = ""; + self.pers[ "best_kill_streak" ] = 0; + } + if ( !isDefined( self.pers[ "music" ] ) ) + { + self.pers[ "music" ] = spawnstruct(); + self.pers[ "music" ].spawn = 0; + self.pers[ "music" ].inque = 0; + self.pers[ "music" ].currentstate = "SILENT"; + self.pers[ "music" ].previousstate = "SILENT"; + self.pers[ "music" ].nextstate = "UNDERSCORE"; + self.pers[ "music" ].returnstate = "UNDERSCORE"; + } + self.leaderdialogqueue = []; + self.leaderdialogactive = 0; + self.leaderdialoggroups = []; + self.currentleaderdialoggroup = ""; + self.currentleaderdialog = ""; + self.currentleaderdialogtime = 0; + if ( !isDefined( self.pers[ "cur_kill_streak" ] ) ) + { + self.pers[ "cur_kill_streak" ] = 0; + } + if ( !isDefined( self.pers[ "cur_total_kill_streak" ] ) ) + { + self.pers[ "cur_total_kill_streak" ] = 0; + self setplayercurrentstreak( 0 ); + } + if ( !isDefined( self.pers[ "totalKillstreakCount" ] ) ) + { + self.pers[ "totalKillstreakCount" ] = 0; + } + if ( !isDefined( self.pers[ "killstreaksEarnedThisKillstreak" ] ) ) + { + self.pers[ "killstreaksEarnedThisKillstreak" ] = 0; + } + if ( isDefined( level.usingscorestreaks ) && level.usingscorestreaks && !isDefined( self.pers[ "killstreak_quantity" ] ) ) + { + self.pers[ "killstreak_quantity" ] = []; + } + if ( isDefined( level.usingscorestreaks ) && level.usingscorestreaks && !isDefined( self.pers[ "held_killstreak_ammo_count" ] ) ) + { + self.pers[ "held_killstreak_ammo_count" ] = []; + } + self.lastkilltime = 0; + self.cur_death_streak = 0; + self disabledeathstreak(); + self.death_streak = 0; + self.kill_streak = 0; + self.gametype_kill_streak = 0; + self.spawnqueueindex = -1; + self.deathtime = 0; + self.lastgrenadesuicidetime = -1; + self.teamkillsthisround = 0; + if ( isDefined( level.livesdonotreset ) || !level.livesdonotreset && !isDefined( self.pers[ "lives" ] ) ) + { + self.pers[ "lives" ] = level.numlives; + } + if ( !level.teambased ) + { + } + self.hasspawned = 0; + self.waitingtospawn = 0; + self.wantsafespawn = 0; + self.deathcount = 0; + self.wasaliveatmatchstart = 0; + level.players[ level.players.size ] = self; + if ( level.splitscreen ) + { + setdvar( "splitscreen_playerNum", level.players.size ); + } + if ( game[ "state" ] == "postgame" ) + { + self.pers[ "needteam" ] = 1; + self.pers[ "team" ] = "spectator"; + self.team = "spectator"; + self setclientuivisibilityflag( "hud_visible", 0 ); + self [[ level.spawnintermission ]](); + self closemenu(); + self closeingamemenu(); + profilelog_endtiming( 4, "gs=" + game[ "state" ] + " zom=" + sessionmodeiszombiesgame() ); + return; + } + if ( level.scr_zm_ui_gametype_group == "zencounter" ) + { + self maps/mp/zombies/_zm_stats::increment_client_stat( "losses" ); + self updatestatratio( "wlratio", "wins", "losses" ); + if ( gamemodeismode( level.gamemode_public_match ) ) + { + self maps/mp/zombies/_zm_stats::add_location_gametype_stat( level.scr_zm_map_start_location, level.scr_zm_ui_gametype, "losses", 1 ); + } + } + else + { + if ( level.scr_zm_ui_gametype_group == "zsurvival" ) + { + if ( is_true( level.should_use_cia ) ) + { + self luinotifyevent( &"hud_update_survival_team", 1, 2 ); + } + } + } + level endon( "game_ended" ); + if ( isDefined( level.hostmigrationtimer ) ) + { + self thread maps/mp/gametypes_zm/_hostmigration::hostmigrationtimerthink(); + } + if ( level.oldschool ) + { + self.class = self.pers[ "class" ]; + } + if ( isDefined( self.pers[ "team" ] ) ) + { + self.team = self.pers[ "team" ]; + } + if ( isDefined( self.pers[ "class" ] ) ) + { + self.class = self.pers[ "class" ]; + } + if ( !isDefined( self.pers[ "team" ] ) || isDefined( self.pers[ "needteam" ] ) ) + { + self.pers[ "team" ] = "spectator"; + self.team = "spectator"; + self.sessionstate = "dead"; + self maps/mp/gametypes_zm/_globallogic_ui::updateobjectivetext(); + [[ level.spawnspectator ]](); + if ( level.rankedmatch ) + { + [[ level.autoassign ]]( 0 ); + self thread maps/mp/gametypes_zm/_globallogic_spawn::kickifdontspawn(); + } + else + { + [[ level.autoassign ]]( 0 ); + } + if ( self.pers[ "team" ] == "spectator" ) + { + self.sessionteam = "spectator"; + if ( !level.teambased ) + { + self.ffateam = "spectator"; + } + self thread spectate_player_watcher(); + } + if ( level.teambased ) + { + self.sessionteam = self.pers[ "team" ]; + if ( !isalive( self ) ) + { + self.statusicon = "hud_status_dead"; + } + self thread maps/mp/gametypes_zm/_spectating::setspectatepermissions(); + } + } + else + { + if ( self.pers[ "team" ] == "spectator" ) + { + self setclientscriptmainmenu( game[ "menu_class" ] ); + [[ level.spawnspectator ]](); + self.sessionteam = "spectator"; + self.sessionstate = "spectator"; + if ( !level.teambased ) + { + self.ffateam = "spectator"; + } + self thread spectate_player_watcher(); + } + else + { + self.sessionteam = self.pers[ "team" ]; + self.sessionstate = "dead"; + if ( !level.teambased ) + { + self.ffateam = self.pers[ "team" ]; + } + self maps/mp/gametypes_zm/_globallogic_ui::updateobjectivetext(); + [[ level.spawnspectator ]](); + if ( maps/mp/gametypes_zm/_globallogic_utils::isvalidclass( self.pers[ "class" ] ) ) + { + self thread [[ level.spawnclient ]](); + } + else + { + self maps/mp/gametypes_zm/_globallogic_ui::showmainmenuforteam(); + } + self thread maps/mp/gametypes_zm/_spectating::setspectatepermissions(); + } + } + if ( self.sessionteam != "spectator" ) + { + self thread maps/mp/gametypes_zm/_spawning::onspawnplayer_unified( 1 ); + } + profilelog_endtiming( 4, "gs=" + game[ "state" ] + " zom=" + sessionmodeiszombiesgame() ); + if ( isDefined( self.pers[ "isBot" ] ) ) + { + return; + } +} + +spectate_player_watcher() +{ + self endon( "disconnect" ); + self.watchingactiveclient = 1; + self.waitingforplayerstext = undefined; + while ( 1 ) + { + if ( self.pers[ "team" ] != "spectator" || level.gameended ) + { + self maps/mp/gametypes_zm/_hud_message::clearshoutcasterwaitingmessage(); +/# + println( " Unfreeze controls 1" ); +#/ + self freezecontrols( 0 ); + self.watchingactiveclient = 0; + return; + } + else if ( !level.splitscreen && !level.hardcoremode && getDvarInt( "scr_showperksonspawn" ) == 1 && game[ "state" ] != "postgame" && !isDefined( self.perkhudelem ) ) + { + if ( level.perksenabled == 1 ) + { + self maps/mp/gametypes_zm/_hud_util::showperks(); + } + self thread maps/mp/gametypes_zm/_globallogic_ui::hideloadoutaftertime( 0 ); + } + count = 0; + i = 0; + while ( i < level.players.size ) + { + if ( level.players[ i ].team != "spectator" ) + { + count++; + break; + } + else + { + i++; + } + } + if ( count > 0 ) + { + if ( !self.watchingactiveclient ) + { + self maps/mp/gametypes_zm/_hud_message::clearshoutcasterwaitingmessage(); + self freezecontrols( 0 ); +/# + println( " Unfreeze controls 2" ); +#/ + } + self.watchingactiveclient = 1; + } + else + { + if ( self.watchingactiveclient ) + { + [[ level.onspawnspectator ]](); + self freezecontrols( 1 ); + self maps/mp/gametypes_zm/_hud_message::setshoutcasterwaitingmessage(); + } + self.watchingactiveclient = 0; + } + wait 0,5; + } +} + +callback_playermigrated() +{ +/# + println( "Player " + self.name + " finished migrating at time " + getTime() ); +#/ + if ( isDefined( self.connected ) && self.connected ) + { + self maps/mp/gametypes_zm/_globallogic_ui::updateobjectivetext(); + } + self thread inform_clientvm_of_migration(); + level.hostmigrationreturnedplayercount++; + if ( level.hostmigrationreturnedplayercount >= ( ( level.players.size * 2 ) / 3 ) ) + { +/# + println( "2/3 of players have finished migrating" ); +#/ + level notify( "hostmigration_enoughplayers" ); + } +} + +inform_clientvm_of_migration() +{ + self endon( "disconnect" ); + wait 1; + self clientnotify( "hmo" ); +/# + println( "SERVER : Sent HMO to client " + self getentitynumber() ); +#/ +} + +callback_playerdisconnect() +{ + profilelog_begintiming( 5, "ship" ); + if ( game[ "state" ] != "postgame" && !level.gameended ) + { + gamelength = maps/mp/gametypes_zm/_globallogic::getgamelength(); + self maps/mp/gametypes_zm/_globallogic::bbplayermatchend( gamelength, "MP_PLAYER_DISCONNECT", 0 ); + } + self removeplayerondisconnect(); + if ( level.splitscreen ) + { + players = level.players; + if ( players.size <= 1 ) + { + level thread maps/mp/gametypes_zm/_globallogic::forceend(); + } + setdvar( "splitscreen_playerNum", players.size ); + } + if ( isDefined( self.score ) && isDefined( self.pers[ "team" ] ) ) + { + self logstring( "team: score " + self.pers[ "team" ] + ":" + self.score ); + level.dropteam += 1; + } + [[ level.onplayerdisconnect ]](); + lpselfnum = self getentitynumber(); + lpguid = self getguid(); + logprint( "Q;" + lpguid + ";" + lpselfnum + ";" + self.name + "\n" ); + entry = 0; + while ( entry < level.players.size ) + { + if ( level.players[ entry ] == self ) + { + while ( entry < ( level.players.size - 1 ) ) + { + level.players[ entry ] = level.players[ entry + 1 ]; + entry++; + } + break; + } + else + { + entry++; + } + } + entry = 0; + while ( entry < level.players.size ) + { + if ( isDefined( level.players[ entry ].pers[ "killed_players" ][ self.name ] ) ) + { + } + if ( isDefined( level.players[ entry ].killedplayerscurrent[ self.name ] ) ) + { + } + if ( isDefined( level.players[ entry ].pers[ "killed_by" ][ self.name ] ) ) + { + } + if ( isDefined( level.players[ entry ].pers[ "nemesis_tracking" ][ self.name ] ) ) + { + } + if ( level.players[ entry ].pers[ "nemesis_name" ] == self.name ) + { + level.players[ entry ] choosenextbestnemesis(); + } + entry++; + } + if ( level.gameended ) + { + self maps/mp/gametypes_zm/_globallogic::removedisconnectedplayerfromplacement(); + } + level thread maps/mp/gametypes_zm/_globallogic::updateteamstatus(); + profilelog_endtiming( 5, "gs=" + game[ "state" ] + " zom=" + sessionmodeiszombiesgame() ); +} + +callback_playermelee( eattacker, idamage, sweapon, vorigin, vdir, boneindex, shieldhit ) +{ + hit = 1; + if ( level.teambased && self.team == eattacker.team ) + { + if ( level.friendlyfire == 0 ) + { + hit = 0; + } + } + self finishmeleehit( eattacker, sweapon, vorigin, vdir, boneindex, shieldhit, hit ); +} + +choosenextbestnemesis() +{ + nemesisarray = self.pers[ "nemesis_tracking" ]; + nemesisarraykeys = getarraykeys( nemesisarray ); + nemesisamount = 0; + nemesisname = ""; + while ( nemesisarraykeys.size > 0 ) + { + i = 0; + while ( i < nemesisarraykeys.size ) + { + nemesisarraykey = nemesisarraykeys[ i ]; + if ( nemesisarray[ nemesisarraykey ] > nemesisamount ) + { + nemesisname = nemesisarraykey; + nemesisamount = nemesisarray[ nemesisarraykey ]; + } + i++; + } + } + self.pers[ "nemesis_name" ] = nemesisname; + if ( nemesisname != "" ) + { + playerindex = 0; + while ( playerindex < level.players.size ) + { + if ( level.players[ playerindex ].name == nemesisname ) + { + nemesisplayer = level.players[ playerindex ]; + self.pers[ "nemesis_rank" ] = nemesisplayer.pers[ "rank" ]; + self.pers[ "nemesis_rankIcon" ] = nemesisplayer.pers[ "rankxp" ]; + self.pers[ "nemesis_xp" ] = nemesisplayer.pers[ "prestige" ]; + self.pers[ "nemesis_xuid" ] = nemesisplayer getxuid( 1 ); + break; + } + else + { + playerindex++; + } + } + } + else self.pers[ "nemesis_xuid" ] = ""; +} + +removeplayerondisconnect() +{ + entry = 0; + while ( entry < level.players.size ) + { + if ( level.players[ entry ] == self ) + { + while ( entry < ( level.players.size - 1 ) ) + { + level.players[ entry ] = level.players[ entry + 1 ]; + entry++; + } + return; + } + else + { + entry++; + } + } +} + +custom_gamemodes_modified_damage( victim, eattacker, idamage, smeansofdeath, sweapon, einflictor, shitloc ) +{ + if ( level.onlinegame && !sessionmodeisprivate() ) + { + return idamage; + } + if ( isDefined( eattacker ) && isDefined( eattacker.damagemodifier ) ) + { + idamage *= eattacker.damagemodifier; + } + if ( smeansofdeath == "MOD_PISTOL_BULLET" || smeansofdeath == "MOD_RIFLE_BULLET" ) + { + idamage = int( idamage * level.bulletdamagescalar ); + } + return idamage; +} + +figureoutattacker( eattacker ) +{ + if ( isDefined( eattacker ) ) + { + if ( isai( eattacker ) && isDefined( eattacker.script_owner ) ) + { + team = self.team; + if ( isai( self ) && isDefined( self.aiteam ) ) + { + team = self.aiteam; + } + if ( eattacker.script_owner.team != team ) + { + eattacker = eattacker.script_owner; + } + } + if ( eattacker.classname == "script_vehicle" && isDefined( eattacker.owner ) ) + { + eattacker = eattacker.owner; + } + else + { + if ( eattacker.classname == "auto_turret" && isDefined( eattacker.owner ) ) + { + eattacker = eattacker.owner; + } + } + } + return eattacker; +} + +figureoutweapon( sweapon, einflictor ) +{ + if ( sweapon == "none" && isDefined( einflictor ) ) + { + if ( isDefined( einflictor.targetname ) && einflictor.targetname == "explodable_barrel" ) + { + sweapon = "explodable_barrel_mp"; + } + else + { + if ( isDefined( einflictor.destructible_type ) && issubstr( einflictor.destructible_type, "vehicle_" ) ) + { + sweapon = "destructible_car_mp"; + } + } + } + return sweapon; +} + +isplayerimmunetokillstreak( eattacker, sweapon ) +{ + if ( level.hardcoremode ) + { + return 0; + } + if ( !isDefined( eattacker ) ) + { + return 0; + } + if ( self != eattacker ) + { + return 0; + } + if ( sweapon != "straferun_gun_mp" && sweapon != "straferun_rockets_mp" ) + { + return 0; + } + return 1; +} + +callback_playerdamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, boneindex ) +{ + profilelog_begintiming( 6, "ship" ); + if ( game[ "state" ] == "postgame" ) + { + return; + } + if ( self.sessionteam == "spectator" ) + { + return; + } + if ( isDefined( self.candocombat ) && !self.candocombat ) + { + return; + } + if ( isDefined( eattacker ) && isplayer( eattacker ) && isDefined( eattacker.candocombat ) && !eattacker.candocombat ) + { + return; + } + if ( isDefined( level.hostmigrationtimer ) ) + { + return; + } + if ( sweapon != "ai_tank_drone_gun_mp" && sweapon == "ai_tank_drone_rocket_mp" && !level.hardcoremode ) + { + if ( isDefined( eattacker ) && eattacker == self ) + { + if ( isDefined( einflictor ) && isDefined( einflictor.from_ai ) ) + { + return; + } + } + if ( isDefined( eattacker ) && isDefined( eattacker.owner ) && eattacker.owner == self ) + { + return; + } + } + if ( sweapon == "emp_grenade_mp" ) + { + self notify( "emp_grenaded" ); + } + idamage = custom_gamemodes_modified_damage( self, eattacker, idamage, smeansofdeath, sweapon, einflictor, shitloc ); + idamage = int( idamage ); + self.idflags = idflags; + self.idflagstime = getTime(); + eattacker = figureoutattacker( eattacker ); + pixbeginevent( "PlayerDamage flags/tweaks" ); + if ( !isDefined( vdir ) ) + { + idflags |= level.idflags_no_knockback; + } + friendly = 0; + if ( self.health != self.maxhealth ) + { + self notify( "snd_pain_player" ); + } + if ( isDefined( einflictor ) && isDefined( einflictor.script_noteworthy ) && einflictor.script_noteworthy == "ragdoll_now" ) + { + smeansofdeath = "MOD_FALLING"; + } + if ( maps/mp/gametypes_zm/_globallogic_utils::isheadshot( sweapon, shitloc, smeansofdeath, einflictor ) && isplayer( eattacker ) ) + { + smeansofdeath = "MOD_HEAD_SHOT"; + } + if ( level.onplayerdamage != ::maps/mp/gametypes_zm/_globallogic::blank ) + { + modifieddamage = [[ level.onplayerdamage ]]( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime ); + if ( isDefined( modifieddamage ) ) + { + if ( modifieddamage <= 0 ) + { + return; + } + idamage = modifieddamage; + } + } + if ( level.onlyheadshots ) + { + if ( smeansofdeath == "MOD_PISTOL_BULLET" || smeansofdeath == "MOD_RIFLE_BULLET" ) + { + return; + } + else + { + if ( smeansofdeath == "MOD_HEAD_SHOT" ) + { + idamage = 150; + } + } + } + if ( isDefined( eattacker ) && isplayer( eattacker ) && self.team != eattacker.team ) + { + self.lastattackweapon = sweapon; + } + sweapon = figureoutweapon( sweapon, einflictor ); + pixendevent(); + if ( isplayer( eattacker ) ) + { + attackerishittingteammate = self isenemyplayer( eattacker ) == 0; + } + if ( shitloc == "riotshield" ) + { + if ( attackerishittingteammate && level.friendlyfire == 0 ) + { + return; + } + if ( smeansofdeath == "MOD_PISTOL_BULLET" || smeansofdeath == "MOD_RIFLE_BULLET" && !attackerishittingteammate ) + { + previous_shield_damage = self.shielddamageblocked; + self.shielddamageblocked += idamage; + if ( isplayer( eattacker ) ) + { + eattacker.lastattackedshieldplayer = self; + eattacker.lastattackedshieldtime = getTime(); + } + if ( ( self.shielddamageblocked % 400 ) < ( previous_shield_damage % 400 ) ) + { + score_event = "shield_blocked_damage"; + if ( self.shielddamageblocked > 2000 ) + { + score_event = "shield_blocked_damage_reduced"; + } + } + } + if ( idflags & level.idflags_shield_explosive_impact ) + { + shitloc = "none"; + if ( idflags & level.idflags_shield_explosive_impact_huge ) + { + idamage *= 0; + } + } + else if ( idflags & level.idflags_shield_explosive_splash ) + { + if ( isDefined( einflictor ) && isDefined( einflictor.stucktoplayer ) && einflictor.stucktoplayer == self ) + { + idamage = 101; + } + shitloc = "none"; + } + else + { + return; + } + } + if ( isDefined( eattacker ) && eattacker != self && !friendly ) + { + level.usestartspawns = 0; + } + pixbeginevent( "PlayerDamage log" ); +/# + if ( getDvarInt( "g_debugDamage" ) ) + { + println( "client:" + self getentitynumber() + " health:" + self.health + " attacker:" + eattacker.clientid + " inflictor is player:" + isplayer( einflictor ) + " damage:" + idamage + " hitLoc:" + shitloc ); +#/ + } + if ( self.sessionstate != "dead" ) + { + lpselfnum = self getentitynumber(); + lpselfname = self.name; + lpselfteam = self.team; + lpselfguid = self getguid(); + lpattackerteam = ""; + lpattackerorigin = ( 0, 0, 0 ); + if ( isplayer( eattacker ) ) + { + lpattacknum = eattacker getentitynumber(); + lpattackguid = eattacker getguid(); + lpattackname = eattacker.name; + lpattackerteam = eattacker.team; + lpattackerorigin = eattacker.origin; + bbprint( "mpattacks", "gametime %d attackerspawnid %d attackerweapon %s attackerx %d attackery %d attackerz %d victimspawnid %d victimx %d victimy %d victimz %d damage %d damagetype %s damagelocation %s death %d", getTime(), getplayerspawnid( eattacker ), sweapon, lpattackerorigin, getplayerspawnid( self ), self.origin, idamage, smeansofdeath, shitloc, 0 ); + } + else + { + lpattacknum = -1; + lpattackguid = ""; + lpattackname = ""; + lpattackerteam = "world"; + bbprint( "mpattacks", "gametime %d attackerweapon %s victimspawnid %d victimx %d victimy %d victimz %d damage %d damagetype %s damagelocation %s death %d", getTime(), sweapon, getplayerspawnid( self ), self.origin, idamage, smeansofdeath, shitloc, 0 ); + } + logprint( "D;" + lpselfguid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sweapon + ";" + idamage + ";" + smeansofdeath + ";" + shitloc + "\n" ); + } + pixendevent(); + profilelog_endtiming( 6, "gs=" + game[ "state" ] + " zom=" + sessionmodeiszombiesgame() ); +} + +resetattackerlist() +{ + self.attackers = []; + self.attackerdata = []; + self.attackerdamage = []; + self.firsttimedamaged = 0; +} + +dodamagefeedback( sweapon, einflictor, idamage, smeansofdeath ) +{ + if ( !isDefined( sweapon ) ) + { + return 0; + } + if ( level.allowhitmarkers == 0 ) + { + return 0; + } + if ( level.allowhitmarkers == 1 ) + { + if ( isDefined( smeansofdeath ) && isDefined( idamage ) ) + { + if ( istacticalhitmarker( sweapon, smeansofdeath, idamage ) ) + { + return 0; + } + } + } + return 1; +} + +istacticalhitmarker( sweapon, smeansofdeath, idamage ) +{ + if ( isgrenade( sweapon ) ) + { + if ( sweapon == "willy_pete_mp" ) + { + if ( smeansofdeath == "MOD_GRENADE_SPLASH" ) + { + return 1; + } + } + else + { + if ( idamage == 1 ) + { + return 1; + } + } + } + return 0; +} + +doperkfeedback( player, sweapon, smeansofdeath, einflictor ) +{ + perkfeedback = undefined; + return perkfeedback; +} + +isaikillstreakdamage( sweapon, einflictor ) +{ + switch( sweapon ) + { + case "ai_tank_drone_rocket_mp": + return isDefined( einflictor.firedbyai ); + case "missile_swarm_projectile_mp": + return 1; + case "planemortar_mp": + return 1; + case "chopper_minigun_mp": + return 1; + case "straferun_rockets_mp": + return 1; + case "littlebird_guard_minigun_mp": + return 1; + case "cobra_20mm_comlink_mp": + return 1; + } + return 0; +} + +finishplayerdamagewrapper( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, boneindex ) +{ + pixbeginevent( "finishPlayerDamageWrapper" ); + if ( !level.console && idflags & level.idflags_penetration && isplayer( eattacker ) ) + { +/# + println( "penetrated:" + self getentitynumber() + " health:" + self.health + " attacker:" + eattacker.clientid + " inflictor is player:" + isplayer( einflictor ) + " damage:" + idamage + " hitLoc:" + shitloc ); +#/ + eattacker addplayerstat( "penetration_shots", 1 ); + } + self finishplayerdamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, boneindex ); + if ( getDvar( #"C8077F47" ) != "" ) + { + self shellshock( "damage_mp", 0,2 ); + } + self damageshellshockandrumble( eattacker, einflictor, sweapon, smeansofdeath, idamage ); + pixendevent(); +} + +allowedassistweapon( weapon ) +{ + return 1; +} + +callback_playerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + profilelog_begintiming( 7, "ship" ); + self endon( "spawned" ); + self notify( "killed_player" ); + if ( self.sessionteam == "spectator" ) + { + return; + } + if ( game[ "state" ] == "postgame" ) + { + return; + } + self needsrevive( 0 ); + if ( isDefined( self.burning ) && self.burning == 1 ) + { + self setburn( 0 ); + } + self.suicide = 0; + if ( isDefined( level.takelivesondeath ) && level.takelivesondeath == 1 ) + { + if ( self.pers[ "lives" ] ) + { + self.pers[ "lives" ]--; + + if ( self.pers[ "lives" ] == 0 ) + { + level notify( "player_eliminated" ); + self notify( "player_eliminated" ); + } + } + } + self thread flushgroupdialogonplayer( "item_destroyed" ); + sweapon = updateweapon( einflictor, sweapon ); + pixbeginevent( "PlayerKilled pre constants" ); + wasinlaststand = 0; + deathtimeoffset = 0; + lastweaponbeforedroppingintolaststand = undefined; + attackerstance = undefined; + self.laststandthislife = undefined; + self.vattackerorigin = undefined; + if ( isDefined( self.uselaststandparams ) ) + { + self.uselaststandparams = undefined; +/# + assert( isDefined( self.laststandparams ) ); +#/ + if ( !level.teambased || isDefined( attacker ) && isplayer( attacker ) || attacker.team != self.team && attacker == self ) + { + einflictor = self.laststandparams.einflictor; + attacker = self.laststandparams.attacker; + attackerstance = self.laststandparams.attackerstance; + idamage = self.laststandparams.idamage; + smeansofdeath = self.laststandparams.smeansofdeath; + sweapon = self.laststandparams.sweapon; + vdir = self.laststandparams.vdir; + shitloc = self.laststandparams.shitloc; + self.vattackerorigin = self.laststandparams.vattackerorigin; + deathtimeoffset = ( getTime() - self.laststandparams.laststandstarttime ) / 1000; + if ( isDefined( self.previousprimary ) ) + { + wasinlaststand = 1; + lastweaponbeforedroppingintolaststand = self.previousprimary; + } + } + self.laststandparams = undefined; + } + bestplayer = undefined; + bestplayermeansofdeath = undefined; + obituarymeansofdeath = undefined; + bestplayerweapon = undefined; + obituaryweapon = undefined; + if ( isDefined( attacker ) && attacker.classname != "trigger_hurt" && attacker.classname != "worldspawn" && isDefined( attacker.ismagicbullet ) && attacker.ismagicbullet != 1 && attacker == self && isDefined( self.attackers ) ) + { + while ( !isDefined( bestplayer ) ) + { + i = 0; + while ( i < self.attackers.size ) + { + player = self.attackers[ i ]; + if ( !isDefined( player ) ) + { + i++; + continue; + } + else if ( !isDefined( self.attackerdamage[ player.clientid ] ) || !isDefined( self.attackerdamage[ player.clientid ].damage ) ) + { + i++; + continue; + } + else + { + if ( player == self || level.teambased && player.team == self.team ) + { + i++; + continue; + } + else + { + if ( ( self.attackerdamage[ player.clientid ].lasttimedamaged + 2500 ) < getTime() ) + { + i++; + continue; + } + else if ( !allowedassistweapon( self.attackerdamage[ player.clientid ].weapon ) ) + { + i++; + continue; + } + else if ( self.attackerdamage[ player.clientid ].damage > 1 && !isDefined( bestplayer ) ) + { + bestplayer = player; + bestplayermeansofdeath = self.attackerdamage[ player.clientid ].meansofdeath; + bestplayerweapon = self.attackerdamage[ player.clientid ].weapon; + i++; + continue; + } + else + { + if ( isDefined( bestplayer ) && self.attackerdamage[ player.clientid ].damage > self.attackerdamage[ bestplayer.clientid ].damage ) + { + bestplayer = player; + bestplayermeansofdeath = self.attackerdamage[ player.clientid ].meansofdeath; + bestplayerweapon = self.attackerdamage[ player.clientid ].weapon; + } + } + } + } + i++; + } + } + if ( isDefined( bestplayer ) ) + { + self recordkillmodifier( "assistedsuicide" ); + } + } + if ( isDefined( bestplayer ) ) + { + attacker = bestplayer; + obituarymeansofdeath = bestplayermeansofdeath; + obituaryweapon = bestplayerweapon; + } + if ( isplayer( attacker ) ) + { + } + if ( maps/mp/gametypes_zm/_globallogic_utils::isheadshot( sweapon, shitloc, smeansofdeath, einflictor ) && isplayer( attacker ) ) + { + attacker playlocalsound( "prj_bullet_impact_headshot_helmet_nodie_2d" ); + smeansofdeath = "MOD_HEAD_SHOT"; + } + self.deathtime = getTime(); + attacker = updateattacker( attacker, sweapon ); + einflictor = updateinflictor( einflictor ); + smeansofdeath = updatemeansofdeath( sweapon, smeansofdeath ); + if ( isDefined( self.hasriotshieldequipped ) && self.hasriotshieldequipped == 1 ) + { + self detachshieldmodel( level.carriedshieldmodel, "tag_weapon_left" ); + self.hasriotshield = 0; + self.hasriotshieldequipped = 0; + } + self thread updateglobalbotkilledcounter(); + if ( isplayer( attacker ) && attacker != self || !level.teambased && level.teambased && self.team != attacker.team ) + { + self addweaponstat( sweapon, "deaths", 1 ); + if ( wasinlaststand && isDefined( lastweaponbeforedroppingintolaststand ) ) + { + weaponname = lastweaponbeforedroppingintolaststand; + } + else + { + weaponname = self.lastdroppableweapon; + } + if ( isDefined( weaponname ) && !issubstr( weaponname, "gl_" ) || issubstr( weaponname, "mk_" ) && issubstr( weaponname, "ft_" ) ) + { + weaponname = self.currentweapon; + } + if ( isDefined( weaponname ) ) + { + self addweaponstat( weaponname, "deathsDuringUse", 1 ); + } + if ( smeansofdeath != "MOD_FALLING" ) + { + attacker addweaponstat( sweapon, "kills", 1 ); + } + if ( smeansofdeath == "MOD_HEAD_SHOT" ) + { + attacker addweaponstat( sweapon, "headshots", 1 ); + } + } + if ( !isDefined( obituarymeansofdeath ) ) + { + obituarymeansofdeath = smeansofdeath; + } + if ( !isDefined( obituaryweapon ) ) + { + obituaryweapon = sweapon; + } + if ( !isplayer( attacker ) || self isenemyplayer( attacker ) == 0 ) + { + level notify( "reset_obituary_count" ); + level.lastobituaryplayercount = 0; + level.lastobituaryplayer = undefined; + } + else + { + if ( isDefined( level.lastobituaryplayer ) && level.lastobituaryplayer == attacker ) + { + level.lastobituaryplayercount++; + } + else + { + level notify( "reset_obituary_count" ); + level.lastobituaryplayer = attacker; + level.lastobituaryplayercount = 1; + } + if ( level.lastobituaryplayercount >= 4 ) + { + level notify( "reset_obituary_count" ); + level.lastobituaryplayercount = 0; + level.lastobituaryplayer = undefined; + } + } + overrideentitycamera = 0; + if ( level.teambased && isDefined( attacker.pers ) && self.team == attacker.team && obituarymeansofdeath == "MOD_GRENADE" && level.friendlyfire == 0 ) + { + obituary( self, self, obituaryweapon, obituarymeansofdeath ); + maps/mp/_demo::bookmark( "kill", getTime(), self, self, 0, einflictor, overrideentitycamera ); + } + else + { + obituary( self, attacker, obituaryweapon, obituarymeansofdeath ); + maps/mp/_demo::bookmark( "kill", getTime(), self, attacker, 0, einflictor, overrideentitycamera ); + } + if ( !level.ingraceperiod ) + { + self maps/mp/gametypes_zm/_weapons::dropscavengerfordeath( attacker ); + self maps/mp/gametypes_zm/_weapons::dropweaponfordeath( attacker ); + self maps/mp/gametypes_zm/_weapons::dropoffhand(); + } + maps/mp/gametypes_zm/_spawnlogic::deathoccured( self, attacker ); + self.sessionstate = "dead"; + self.statusicon = "hud_status_dead"; + self.killedplayerscurrent = []; + self.deathcount++; +/# + println( "players(" + self.clientid + ") death count ++: " + self.deathcount ); +#/ + if ( !isDefined( self.switching_teams ) ) + { + if ( isplayer( attacker ) && level.teambased && attacker != self && self.team == attacker.team ) + { + self.pers[ "cur_kill_streak" ] = 0; + self.pers[ "cur_total_kill_streak" ] = 0; + self.pers[ "totalKillstreakCount" ] = 0; + self.pers[ "killstreaksEarnedThisKillstreak" ] = 0; + self setplayercurrentstreak( 0 ); + } + else + { + self maps/mp/gametypes_zm/_globallogic_score::incpersstat( "deaths", 1, 1, 1 ); + self.deaths = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "deaths" ); + self updatestatratio( "kdratio", "kills", "deaths" ); + if ( self.pers[ "cur_kill_streak" ] > self.pers[ "best_kill_streak" ] ) + { + self.pers[ "best_kill_streak" ] = self.pers[ "cur_kill_streak" ]; + } + self.pers[ "kill_streak_before_death" ] = self.pers[ "cur_kill_streak" ]; + self.pers[ "cur_kill_streak" ] = 0; + self.pers[ "cur_total_kill_streak" ] = 0; + self.pers[ "totalKillstreakCount" ] = 0; + self.pers[ "killstreaksEarnedThisKillstreak" ] = 0; + self setplayercurrentstreak( 0 ); + self.cur_death_streak++; + if ( self.cur_death_streak > self.death_streak ) + { + if ( level.rankedmatch ) + { + self setdstat( "HighestStats", "death_streak", self.cur_death_streak ); + } + self.death_streak = self.cur_death_streak; + } + if ( self.cur_death_streak >= getDvarInt( "perk_deathStreakCountRequired" ) ) + { + self enabledeathstreak(); + } + } + } + else + { + self.pers[ "totalKillstreakCount" ] = 0; + self.pers[ "killstreaksEarnedThisKillstreak" ] = 0; + } + lpselfnum = self getentitynumber(); + lpselfname = self.name; + lpattackguid = ""; + lpattackname = ""; + lpselfteam = self.team; + lpselfguid = self getguid(); + lpattackteam = ""; + lpattackorigin = ( 0, 0, 0 ); + lpattacknum = -1; + awardassists = 0; + pixendevent(); + self resetplayermomentumondeath(); + if ( isplayer( attacker ) ) + { + lpattackguid = attacker getguid(); + lpattackname = attacker.name; + lpattackteam = attacker.team; + lpattackorigin = attacker.origin; + if ( attacker == self ) + { + dokillcam = 0; + self maps/mp/gametypes_zm/_globallogic_score::incpersstat( "suicides", 1 ); + self.suicides = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "suicides" ); + if ( smeansofdeath == "MOD_SUICIDE" && shitloc == "none" && self.throwinggrenade ) + { + self.lastgrenadesuicidetime = getTime(); + } + awardassists = 1; + self.suicide = 1; + if ( isDefined( self.friendlydamage ) ) + { + self iprintln( &"MP_FRIENDLY_FIRE_WILL_NOT" ); + if ( level.teamkillpointloss ) + { + scoresub = self [[ level.getteamkillscore ]]( einflictor, attacker, smeansofdeath, sweapon ); + maps/mp/gametypes_zm/_globallogic_score::_setplayerscore( attacker, maps/mp/gametypes_zm/_globallogic_score::_getplayerscore( attacker ) - scoresub ); + } + } + } + else + { + pixbeginevent( "PlayerKilled attacker" ); + lpattacknum = attacker getentitynumber(); + dokillcam = 1; + if ( level.teambased && self.team == attacker.team && smeansofdeath == "MOD_GRENADE" && level.friendlyfire == 0 ) + { + } + else + { + if ( level.teambased && self.team == attacker.team ) + { + if ( !ignoreteamkills( sweapon, smeansofdeath ) ) + { + teamkill_penalty = self [[ level.getteamkillpenalty ]]( einflictor, attacker, smeansofdeath, sweapon ); + attacker maps/mp/gametypes_zm/_globallogic_score::incpersstat( "teamkills_nostats", teamkill_penalty, 0 ); + attacker maps/mp/gametypes_zm/_globallogic_score::incpersstat( "teamkills", 1 ); + attacker.teamkillsthisround++; + if ( level.teamkillpointloss ) + { + scoresub = self [[ level.getteamkillscore ]]( einflictor, attacker, smeansofdeath, sweapon ); + maps/mp/gametypes_zm/_globallogic_score::_setplayerscore( attacker, maps/mp/gametypes_zm/_globallogic_score::_getplayerscore( attacker ) - scoresub ); + } + if ( maps/mp/gametypes_zm/_globallogic_utils::gettimepassed() < 5000 ) + { + teamkilldelay = 1; + } + else if ( attacker.pers[ "teamkills_nostats" ] > 1 && maps/mp/gametypes_zm/_globallogic_utils::gettimepassed() < ( 8000 + ( attacker.pers[ "teamkills_nostats" ] * 1000 ) ) ) + { + teamkilldelay = 1; + } + else + { + teamkilldelay = attacker teamkilldelay(); + } + if ( teamkilldelay > 0 ) + { + attacker.teamkillpunish = 1; + attacker suicide(); + if ( attacker shouldteamkillkick( teamkilldelay ) ) + { + attacker teamkillkick(); + } + attacker thread reduceteamkillsovertime(); + } + } + } + else + { + maps/mp/gametypes_zm/_globallogic_score::inctotalkills( attacker.team ); + attacker thread maps/mp/gametypes_zm/_globallogic_score::givekillstats( smeansofdeath, sweapon, self ); + if ( isalive( attacker ) ) + { + pixbeginevent( "killstreak" ); + if ( isDefined( einflictor ) || !isDefined( einflictor.requireddeathcount ) && attacker.deathcount == einflictor.requireddeathcount ) + { + shouldgivekillstreak = 0; + attacker.pers[ "cur_total_kill_streak" ]++; + attacker setplayercurrentstreak( attacker.pers[ "cur_total_kill_streak" ] ); + if ( isDefined( level.killstreaks ) && shouldgivekillstreak ) + { + attacker.pers[ "cur_kill_streak" ]++; + if ( attacker.pers[ "cur_kill_streak" ] >= 3 ) + { + if ( attacker.pers[ "cur_kill_streak" ] <= 30 ) + { + } + } + } + } + pixendevent(); + } + if ( attacker.pers[ "cur_kill_streak" ] > attacker.kill_streak ) + { + if ( level.rankedmatch ) + { + attacker setdstat( "HighestStats", "kill_streak", attacker.pers[ "totalKillstreakCount" ] ); + } + attacker.kill_streak = attacker.pers[ "cur_kill_streak" ]; + } + killstreak = undefined; + if ( isDefined( killstreak ) ) + { + } + else if ( smeansofdeath == "MOD_HEAD_SHOT" ) + { + } + else if ( smeansofdeath == "MOD_MELEE" ) + { + if ( sweapon == "riotshield_mp" ) + { + } + } + attacker thread maps/mp/gametypes_zm/_globallogic_score::trackattackerkill( self.name, self.pers[ "rank" ], self.pers[ "rankxp" ], self.pers[ "prestige" ], self getxuid( 1 ) ); + attackername = attacker.name; + self thread maps/mp/gametypes_zm/_globallogic_score::trackattackeedeath( attackername, attacker.pers[ "rank" ], attacker.pers[ "rankxp" ], attacker.pers[ "prestige" ], attacker getxuid( 1 ) ); + attacker thread maps/mp/gametypes_zm/_globallogic_score::inckillstreaktracker( sweapon ); + if ( level.teambased && attacker.team != "spectator" ) + { + if ( isai( attacker ) ) + { + maps/mp/gametypes_zm/_globallogic_score::giveteamscore( "kill", attacker.aiteam, attacker, self ); + } + else + { + maps/mp/gametypes_zm/_globallogic_score::giveteamscore( "kill", attacker.team, attacker, self ); + } + } + scoresub = level.deathpointloss; + if ( scoresub != 0 ) + { + maps/mp/gametypes_zm/_globallogic_score::_setplayerscore( self, maps/mp/gametypes_zm/_globallogic_score::_getplayerscore( self ) - scoresub ); + } + level thread playkillbattlechatter( attacker, sweapon, self ); + if ( level.teambased ) + { + awardassists = 1; + } + } + } + pixendevent(); + } + } + else if ( isDefined( attacker ) || attacker.classname == "trigger_hurt" && attacker.classname == "worldspawn" ) + { + dokillcam = 0; + lpattacknum = -1; + lpattackguid = ""; + lpattackname = ""; + lpattackteam = "world"; + self maps/mp/gametypes_zm/_globallogic_score::incpersstat( "suicides", 1 ); + self.suicides = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "suicides" ); + awardassists = 1; + } + else + { + dokillcam = 0; + lpattacknum = -1; + lpattackguid = ""; + lpattackname = ""; + lpattackteam = "world"; + if ( isDefined( einflictor ) && isDefined( einflictor.killcament ) ) + { + dokillcam = 1; + lpattacknum = self getentitynumber(); + } + if ( isDefined( attacker ) && isDefined( attacker.team ) && isDefined( level.teams[ attacker.team ] ) ) + { + if ( attacker.team != self.team ) + { + if ( level.teambased ) + { + maps/mp/gametypes_zm/_globallogic_score::giveteamscore( "kill", attacker.team, attacker, self ); + } + } + } + awardassists = 1; + } + if ( sessionmodeiszombiesgame() ) + { + awardassists = 0; + } + if ( awardassists ) + { + pixbeginevent( "PlayerKilled assists" ); + while ( isDefined( self.attackers ) ) + { + j = 0; + while ( j < self.attackers.size ) + { + player = self.attackers[ j ]; + if ( !isDefined( player ) ) + { + j++; + continue; + } + else if ( player == attacker ) + { + j++; + continue; + } + else if ( player.team != lpattackteam ) + { + j++; + continue; + } + else + { + damage_done = self.attackerdamage[ player.clientid ].damage; + player thread maps/mp/gametypes_zm/_globallogic_score::processassist( self, damage_done, self.attackerdamage[ player.clientid ].weapon ); + } + j++; + } + } + if ( isDefined( self.lastattackedshieldplayer ) && isDefined( self.lastattackedshieldtime ) && self.lastattackedshieldplayer != attacker ) + { + if ( ( getTime() - self.lastattackedshieldtime ) < 4000 ) + { + self.lastattackedshieldplayer thread maps/mp/gametypes_zm/_globallogic_score::processshieldassist( self ); + } + } + pixendevent(); + } + pixbeginevent( "PlayerKilled post constants" ); + self.lastattacker = attacker; + self.lastdeathpos = self.origin; + if ( isDefined( attacker ) && isplayer( attacker ) && attacker != self || !level.teambased && attacker.team != self.team ) + { + self thread maps/mp/_challenges::playerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, shitloc, attackerstance ); + } + else + { + self notify( "playerKilledChallengesProcessed" ); + } + if ( isDefined( self.attackers ) ) + { + self.attackers = []; + } + if ( isplayer( attacker ) ) + { + bbprint( "mpattacks", "gametime %d attackerspawnid %d attackerweapon %s attackerx %d attackery %d attackerz %d victimspawnid %d victimx %d victimy %d victimz %d damage %d damagetype %s damagelocation %s death %d", getTime(), getplayerspawnid( attacker ), sweapon, lpattackorigin, getplayerspawnid( self ), self.origin, idamage, smeansofdeath, shitloc, 1 ); + } + else + { + bbprint( "mpattacks", "gametime %d attackerweapon %s victimspawnid %d victimx %d victimy %d victimz %d damage %d damagetype %s damagelocation %s death %d", getTime(), sweapon, getplayerspawnid( self ), self.origin, idamage, smeansofdeath, shitloc, 1 ); + } + logprint( "K;" + lpselfguid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackteam + ";" + lpattackname + ";" + sweapon + ";" + idamage + ";" + smeansofdeath + ";" + shitloc + "\n" ); + attackerstring = "none"; + if ( isplayer( attacker ) ) + { + attackerstring = attacker getxuid() + "(" + lpattackname + ")"; + } + self logstring( "d " + smeansofdeath + "(" + sweapon + ") a:" + attackerstring + " d:" + idamage + " l:" + shitloc + " @ " + int( self.origin[ 0 ] ) + " " + int( self.origin[ 1 ] ) + " " + int( self.origin[ 2 ] ) ); + level thread maps/mp/gametypes_zm/_globallogic::updateteamstatus(); + killcamentity = self getkillcamentity( attacker, einflictor, sweapon ); + killcamentityindex = -1; + killcamentitystarttime = 0; + if ( isDefined( killcamentity ) ) + { + killcamentityindex = killcamentity getentitynumber(); + if ( isDefined( killcamentity.starttime ) ) + { + killcamentitystarttime = killcamentity.starttime; + } + else + { + killcamentitystarttime = killcamentity.birthtime; + } + if ( !isDefined( killcamentitystarttime ) ) + { + killcamentitystarttime = 0; + } + } + if ( isDefined( self.killstreak_waitamount ) && self.killstreak_waitamount > 0 ) + { + dokillcam = 0; + } + self maps/mp/gametypes_zm/_weapons::detachcarryobjectmodel(); + died_in_vehicle = 0; + if ( isDefined( self.diedonvehicle ) ) + { + died_in_vehicle = self.diedonvehicle; + } + pixendevent(); + pixbeginevent( "PlayerKilled body and gibbing" ); + if ( !died_in_vehicle ) + { + vattackerorigin = undefined; + if ( isDefined( attacker ) ) + { + vattackerorigin = attacker.origin; + } + ragdoll_now = 0; + if ( isDefined( self.usingvehicle ) && self.usingvehicle && isDefined( self.vehicleposition ) && self.vehicleposition == 1 ) + { + ragdoll_now = 1; + } + body = self cloneplayer( deathanimduration ); + self createdeadbody( idamage, smeansofdeath, sweapon, shitloc, vdir, vattackerorigin, deathanimduration, einflictor, ragdoll_now, body ); + } + pixendevent(); + thread maps/mp/gametypes_zm/_globallogic_spawn::spawnqueuedclient( self.team, attacker ); + self.switching_teams = undefined; + self.joining_team = undefined; + self.leaving_team = undefined; + self thread [[ level.onplayerkilled ]]( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ); + icb = 0; + while ( icb < level.onplayerkilledextraunthreadedcbs.size ) + { + self [[ level.onplayerkilledextraunthreadedcbs[ icb ] ]]( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ); + icb++; + } + self.wantsafespawn = 0; + perks = []; + killstreaks = maps/mp/gametypes_zm/_globallogic::getkillstreaks( attacker ); + if ( !isDefined( self.killstreak_waitamount ) ) + { + self thread [[ level.spawnplayerprediction ]](); + } + profilelog_endtiming( 7, "gs=" + game[ "state" ] + " zom=" + sessionmodeiszombiesgame() ); + wait 0,25; + weaponclass = getweaponclass( sweapon ); + self.cancelkillcam = 0; + defaultplayerdeathwatchtime = 1,75; + if ( isDefined( level.overrideplayerdeathwatchtimer ) ) + { + defaultplayerdeathwatchtime = [[ level.overrideplayerdeathwatchtimer ]]( defaultplayerdeathwatchtime ); + } + maps/mp/gametypes_zm/_globallogic_utils::waitfortimeornotifies( defaultplayerdeathwatchtime ); + self notify( "death_delay_finished" ); +/# + if ( getDvarInt( #"C1849218" ) != 0 ) + { + dokillcam = 1; + if ( lpattacknum < 0 ) + { + lpattacknum = self getentitynumber(); +#/ + } + } + if ( game[ "state" ] != "playing" ) + { + return; + } + self.respawntimerstarttime = getTime(); + if ( !self.cancelkillcam && dokillcam && level.killcam ) + { + if ( level.numliveslivesleft = self.pers[ "lives" ]; + timeuntilspawn = maps/mp/gametypes_zm/_globallogic_spawn::timeuntilspawn( 1 ); + && livesleft && timeuntilspawn <= 0 ) + { + willrespawnimmediately = !level.playerqueuedrespawn; + } + } + if ( game[ "state" ] != "playing" ) + { + self.sessionstate = "dead"; + self.spectatorclient = -1; + self.killcamtargetentity = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + return; + } + waittillkillstreakdone(); + if ( maps/mp/gametypes_zm/_globallogic_utils::isvalidclass( self.class ) ) + { + timepassed = undefined; + if ( isDefined( self.respawntimerstarttime ) ) + { + timepassed = ( getTime() - self.respawntimerstarttime ) / 1000; + } + self thread [[ level.spawnclient ]]( timepassed ); + self.respawntimerstarttime = undefined; + } +} + +updateglobalbotkilledcounter() +{ + if ( isDefined( self.pers[ "isBot" ] ) ) + { + level.globallarryskilled++; + } +} + +waittillkillstreakdone() +{ + if ( isDefined( self.killstreak_waitamount ) ) + { + starttime = getTime(); + waittime = self.killstreak_waitamount * 1000; + while ( getTime() < ( starttime + waittime ) && isDefined( self.killstreak_waitamount ) ) + { + wait 0,1; + } + wait 2; + self.killstreak_waitamount = undefined; + } +} + +teamkillkick() +{ + self maps/mp/gametypes_zm/_globallogic_score::incpersstat( "sessionbans", 1 ); + self endon( "disconnect" ); + waittillframeend; + playlistbanquantum = maps/mp/gametypes_zm/_tweakables::gettweakablevalue( "team", "teamkillerplaylistbanquantum" ); + playlistbanpenalty = maps/mp/gametypes_zm/_tweakables::gettweakablevalue( "team", "teamkillerplaylistbanpenalty" ); + if ( playlistbanquantum > 0 && playlistbanpenalty > 0 ) + { + timeplayedtotal = self getdstat( "playerstatslist", "time_played_total", "StatValue" ); + minutesplayed = timeplayedtotal / 60; + freebees = 2; + banallowance = int( floor( minutesplayed / playlistbanquantum ) ) + freebees; + if ( self.sessionbans > banallowance ) + { + self setdstat( "playerstatslist", "gametypeban", "StatValue", timeplayedtotal + ( playlistbanpenalty * 60 ) ); + } + } + if ( self is_bot() ) + { + level notify( "bot_kicked" ); + } + ban( self getentitynumber() ); + maps/mp/gametypes_zm/_globallogic_audio::leaderdialog( "kicked" ); +} + +teamkilldelay() +{ + teamkills = self.pers[ "teamkills_nostats" ]; + if ( level.minimumallowedteamkills < 0 || teamkills <= level.minimumallowedteamkills ) + { + return 0; + } + exceeded = teamkills - level.minimumallowedteamkills; + return level.teamkillspawndelay * exceeded; +} + +shouldteamkillkick( teamkilldelay ) +{ + if ( teamkilldelay && level.minimumallowedteamkills >= 0 ) + { + if ( maps/mp/gametypes_zm/_globallogic_utils::gettimepassed() >= 5000 ) + { + return 1; + } + if ( self.pers[ "teamkills_nostats" ] > 1 ) + { + return 1; + } + } + return 0; +} + +reduceteamkillsovertime() +{ + timeperoneteamkillreduction = 20; + reductionpersecond = 1 / timeperoneteamkillreduction; + while ( 1 ) + { + if ( isalive( self ) ) + { + self.pers[ "teamkills_nostats" ] -= reductionpersecond; + if ( self.pers[ "teamkills_nostats" ] < level.minimumallowedteamkills ) + { + self.pers[ "teamkills_nostats" ] = level.minimumallowedteamkills; + return; + } + } + else + { + wait 1; + } + } +} + +ignoreteamkills( sweapon, smeansofdeath ) +{ + if ( sessionmodeiszombiesgame() ) + { + return 1; + } + if ( smeansofdeath == "MOD_MELEE" ) + { + return 0; + } + if ( sweapon == "briefcase_bomb_mp" ) + { + return 1; + } + if ( sweapon == "supplydrop_mp" ) + { + return 1; + } + return 0; +} + +callback_playerlaststand( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ +} + +damageshellshockandrumble( eattacker, einflictor, sweapon, smeansofdeath, idamage ) +{ + self thread maps/mp/gametypes_zm/_weapons::onweapondamage( eattacker, einflictor, sweapon, smeansofdeath, idamage ); + self playrumbleonentity( "damage_heavy" ); +} + +createdeadbody( idamage, smeansofdeath, sweapon, shitloc, vdir, vattackerorigin, deathanimduration, einflictor, ragdoll_jib, body ) +{ + if ( smeansofdeath == "MOD_HIT_BY_OBJECT" && self getstance() == "prone" ) + { + self.body = body; + return; + } + if ( isDefined( level.ragdoll_override ) && self [[ level.ragdoll_override ]]() ) + { + return; + } + if ( !ragdoll_jib && !self isonladder() && !self ismantling() || smeansofdeath == "MOD_CRUSH" && smeansofdeath == "MOD_HIT_BY_OBJECT" ) + { + body startragdoll(); + } + if ( !self isonground() ) + { + if ( getDvarInt( "scr_disable_air_death_ragdoll" ) == 0 ) + { + body startragdoll(); + } + } + if ( self is_explosive_ragdoll( sweapon, einflictor ) ) + { + body start_explosive_ragdoll( vdir, sweapon ); + } + thread delaystartragdoll( body, shitloc, vdir, sweapon, einflictor, smeansofdeath ); + self.body = body; +} + +is_explosive_ragdoll( weapon, inflictor ) +{ + if ( !isDefined( weapon ) ) + { + return 0; + } + if ( weapon == "destructible_car_mp" || weapon == "explodable_barrel_mp" ) + { + return 1; + } + if ( weapon == "sticky_grenade_mp" || weapon == "explosive_bolt_mp" ) + { + if ( isDefined( inflictor ) && isDefined( inflictor.stucktoplayer ) ) + { + if ( inflictor.stucktoplayer == self ) + { + return 1; + } + } + } + return 0; +} + +start_explosive_ragdoll( dir, weapon ) +{ + if ( !isDefined( self ) ) + { + return; + } + x = randomintrange( 50, 100 ); + y = randomintrange( 50, 100 ); + z = randomintrange( 10, 20 ); + if ( isDefined( weapon ) || weapon == "sticky_grenade_mp" && weapon == "explosive_bolt_mp" ) + { + if ( isDefined( dir ) && lengthsquared( dir ) > 0 ) + { + x = dir[ 0 ] * x; + y = dir[ 1 ] * y; + } + } + else + { + if ( cointoss() ) + { + x *= -1; + } + if ( cointoss() ) + { + y *= -1; + } + } + self startragdoll(); + self launchragdoll( ( x, y, z ) ); +} + +notifyconnecting() +{ + waittillframeend; + if ( isDefined( self ) ) + { + level notify( "connecting" ); + } +} + +delaystartragdoll( ent, shitloc, vdir, sweapon, einflictor, smeansofdeath ) +{ + if ( isDefined( ent ) ) + { + deathanim = ent getcorpseanim(); + if ( animhasnotetrack( deathanim, "ignore_ragdoll" ) ) + { + return; + } + } + if ( level.oldschool ) + { + if ( !isDefined( vdir ) ) + { + vdir = ( 0, 0, 0 ); + } + explosionpos = ent.origin + ( 0, 0, maps/mp/gametypes_zm/_globallogic_utils::gethitlocheight( shitloc ) ); + explosionpos -= vdir * 20; + explosionradius = 40; + explosionforce = 0,75; + if ( smeansofdeath != "MOD_IMPACT" && smeansofdeath != "MOD_EXPLOSIVE" && !issubstr( smeansofdeath, "MOD_GRENADE" ) && !issubstr( smeansofdeath, "MOD_PROJECTILE" ) || shitloc == "head" && shitloc == "helmet" ) + { + explosionforce = 2,5; + } + ent startragdoll( 1 ); + wait 0,05; + if ( !isDefined( ent ) ) + { + return; + } + physicsexplosionsphere( explosionpos, explosionradius, explosionradius / 2, explosionforce ); + return; + } + wait 0,2; + if ( !isDefined( ent ) ) + { + return; + } + if ( ent isragdoll() ) + { + return; + } + deathanim = ent getcorpseanim(); + startfrac = 0,35; + if ( animhasnotetrack( deathanim, "start_ragdoll" ) ) + { + times = getnotetracktimes( deathanim, "start_ragdoll" ); + if ( isDefined( times ) ) + { + startfrac = times[ 0 ]; + } + } + waittime = startfrac * getanimlength( deathanim ); + wait waittime; + if ( isDefined( ent ) ) + { + ent startragdoll( 1 ); + } +} + +trackattackerdamage( eattacker, idamage, smeansofdeath, sweapon ) +{ +/# + assert( isplayer( eattacker ) ); +#/ + if ( self.attackerdata.size == 0 ) + { + self.firsttimedamaged = getTime(); + } + if ( !isDefined( self.attackerdata[ eattacker.clientid ] ) ) + { + self.attackerdamage[ eattacker.clientid ] = spawnstruct(); + self.attackerdamage[ eattacker.clientid ].damage = idamage; + self.attackerdamage[ eattacker.clientid ].meansofdeath = smeansofdeath; + self.attackerdamage[ eattacker.clientid ].weapon = sweapon; + self.attackerdamage[ eattacker.clientid ].time = getTime(); + self.attackers[ self.attackers.size ] = eattacker; + self.attackerdata[ eattacker.clientid ] = 0; + } + else + { + self.attackerdamage[ eattacker.clientid ].damage += idamage; + self.attackerdamage[ eattacker.clientid ].meansofdeath = smeansofdeath; + self.attackerdamage[ eattacker.clientid ].weapon = sweapon; + if ( !isDefined( self.attackerdamage[ eattacker.clientid ].time ) ) + { + self.attackerdamage[ eattacker.clientid ].time = getTime(); + } + } + self.attackerdamage[ eattacker.clientid ].lasttimedamaged = getTime(); + if ( maps/mp/gametypes_zm/_weapons::isprimaryweapon( sweapon ) ) + { + self.attackerdata[ eattacker.clientid ] = 1; + } +} + +giveinflictorownerassist( eattacker, einflictor, idamage, smeansofdeath, sweapon ) +{ + if ( !isDefined( einflictor ) ) + { + return; + } + if ( !isDefined( einflictor.owner ) ) + { + return; + } + if ( !isDefined( einflictor.ownergetsassist ) ) + { + return; + } + if ( !einflictor.ownergetsassist ) + { + return; + } +/# + assert( isplayer( einflictor.owner ) ); +#/ + self trackattackerdamage( einflictor.owner, idamage, smeansofdeath, sweapon ); +} + +updatemeansofdeath( sweapon, smeansofdeath ) +{ + switch( sweapon ) + { + case "crossbow_mp": + case "knife_ballistic_mp": + if ( smeansofdeath != "MOD_HEAD_SHOT" && smeansofdeath != "MOD_MELEE" ) + { + smeansofdeath = "MOD_PISTOL_BULLET"; + } + break; + case "dog_bite_mp": + smeansofdeath = "MOD_PISTOL_BULLET"; + break; + case "destructible_car_mp": + smeansofdeath = "MOD_EXPLOSIVE"; + break; + case "explodable_barrel_mp": + smeansofdeath = "MOD_EXPLOSIVE"; + break; + } + return smeansofdeath; +} + +updateattacker( attacker, weapon ) +{ + if ( isai( attacker ) && isDefined( attacker.script_owner ) ) + { + if ( !level.teambased || attacker.script_owner.team != self.team ) + { + attacker = attacker.script_owner; + } + } + if ( attacker.classname == "script_vehicle" && isDefined( attacker.owner ) ) + { + attacker notify( "killed" ); + attacker = attacker.owner; + } + if ( isai( attacker ) ) + { + attacker notify( "killed" ); + } + if ( isDefined( self.capturinglastflag ) && self.capturinglastflag == 1 ) + { + attacker.lastcapkiller = 1; + } + if ( isDefined( attacker ) && isDefined( weapon ) && weapon == "planemortar_mp" ) + { + if ( !isDefined( attacker.planemortarbda ) ) + { + attacker.planemortarbda = 0; + } + attacker.planemortarbda++; + } + return attacker; +} + +updateinflictor( einflictor ) +{ + if ( isDefined( einflictor ) && einflictor.classname == "script_vehicle" ) + { + einflictor notify( "killed" ); + if ( isDefined( einflictor.bda ) ) + { + einflictor.bda++; + } + } + return einflictor; +} + +updateweapon( einflictor, sweapon ) +{ + if ( sweapon == "none" && isDefined( einflictor ) ) + { + if ( isDefined( einflictor.targetname ) && einflictor.targetname == "explodable_barrel" ) + { + sweapon = "explodable_barrel_mp"; + } + else + { + if ( isDefined( einflictor.destructible_type ) && issubstr( einflictor.destructible_type, "vehicle_" ) ) + { + sweapon = "destructible_car_mp"; + } + } + } + return sweapon; +} + +getclosestkillcamentity( attacker, killcamentities, depth ) +{ + if ( !isDefined( depth ) ) + { + depth = 0; + } + closestkillcament = undefined; + closestkillcamentindex = undefined; + closestkillcamentdist = undefined; + origin = undefined; + _a2796 = killcamentities; + killcamentindex = getFirstArrayKey( _a2796 ); + while ( isDefined( killcamentindex ) ) + { + killcament = _a2796[ killcamentindex ]; + if ( killcament == attacker ) + { + } + else + { + origin = killcament.origin; + if ( isDefined( killcament.offsetpoint ) ) + { + origin += killcament.offsetpoint; + } + dist = distancesquared( self.origin, origin ); + if ( !isDefined( closestkillcament ) || dist < closestkillcamentdist ) + { + closestkillcament = killcament; + closestkillcamentdist = dist; + closestkillcamentindex = killcamentindex; + } + } + killcamentindex = getNextArrayKey( _a2796, killcamentindex ); + } + if ( depth < 3 && isDefined( closestkillcament ) ) + { + if ( !bullettracepassed( closestkillcament.origin, self.origin, 0, self ) ) + { + betterkillcament = getclosestkillcamentity( attacker, killcamentities, depth + 1 ); + if ( isDefined( betterkillcament ) ) + { + closestkillcament = betterkillcament; + } + } + } + return closestkillcament; +} + +getkillcamentity( attacker, einflictor, sweapon ) +{ + if ( !isDefined( einflictor ) ) + { + return undefined; + } + if ( einflictor == attacker ) + { + if ( !isDefined( einflictor.ismagicbullet ) ) + { + return undefined; + } + if ( isDefined( einflictor.ismagicbullet ) && !einflictor.ismagicbullet ) + { + return undefined; + } + } + else + { + if ( isDefined( level.levelspecifickillcam ) ) + { + levelspecifickillcament = self [[ level.levelspecifickillcam ]](); + if ( isDefined( levelspecifickillcament ) ) + { + return levelspecifickillcament; + } + } + } + if ( sweapon == "m220_tow_mp" ) + { + return undefined; + } + if ( isDefined( einflictor.killcament ) ) + { + if ( einflictor.killcament == attacker ) + { + return undefined; + } + return einflictor.killcament; + } + else + { + if ( isDefined( einflictor.killcamentities ) ) + { + return getclosestkillcamentity( attacker, einflictor.killcamentities ); + } + } + if ( isDefined( einflictor.script_gameobjectname ) && einflictor.script_gameobjectname == "bombzone" ) + { + return einflictor.killcament; + } + return einflictor; +} + +playkillbattlechatter( attacker, sweapon, victim ) +{ +} diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic_score.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic_score.gsc new file mode 100644 index 0000000..a5610a2 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic_score.gsc @@ -0,0 +1,873 @@ +#include maps/mp/gametypes_zm/_globallogic_utils; +#include maps/mp/_challenges; +#include maps/mp/gametypes_zm/_globallogic_audio; +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/gametypes_zm/_globallogic; +#include maps/mp/_bb; +#include maps/mp/_utility; +#include common_scripts/utility; + +updatematchbonusscores( winner ) +{ +} + +givematchbonus( scoretype, score ) +{ +} + +doskillupdate( winner ) +{ + skillupdate( winner, level.teambased ); +} + +gethighestscoringplayer() +{ + players = level.players; + winner = undefined; + tie = 0; + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ].score ) ) + { + i++; + continue; + } + else if ( players[ i ].score < 1 ) + { + i++; + continue; + } + else if ( !isDefined( winner ) || players[ i ].score > winner.score ) + { + winner = players[ i ]; + tie = 0; + i++; + continue; + } + else + { + if ( players[ i ].score == winner.score ) + { + tie = 1; + } + } + i++; + } + if ( tie || !isDefined( winner ) ) + { + return undefined; + } + else + { + return winner; + } +} + +resetscorechain() +{ + self notify( "reset_score_chain" ); + self.scorechain = 0; + self.rankupdatetotal = 0; +} + +scorechaintimer() +{ + self notify( "score_chain_timer" ); + self endon( "reset_score_chain" ); + self endon( "score_chain_timer" ); + self endon( "death" ); + self endon( "disconnect" ); + wait 20; + self thread resetscorechain(); +} + +roundtonearestfive( score ) +{ + rounding = score % 5; + if ( rounding <= 2 ) + { + return score - rounding; + } + else + { + return score + ( 5 - rounding ); + } +} + +giveplayermomentumnotification( score, label, descvalue, countstowardrampage ) +{ + rampagebonus = 0; + if ( isDefined( level.usingrampage ) && level.usingrampage ) + { + if ( countstowardrampage ) + { + if ( !isDefined( self.scorechain ) ) + { + self.scorechain = 0; + } + self.scorechain++; + self thread scorechaintimer(); + } + if ( isDefined( self.scorechain ) && self.scorechain >= 999 ) + { + rampagebonus = roundtonearestfive( int( ( score * level.rampagebonusscale ) + 0,5 ) ); + } + } + if ( score != 0 ) + { + self luinotifyevent( &"score_event", 3, label, score, rampagebonus ); + } + score += rampagebonus; + if ( score > 0 && self hasperk( "specialty_earnmoremomentum" ) ) + { + score = roundtonearestfive( int( ( score * getDvarFloat( "perk_killstreakMomentumMultiplier" ) ) + 0,5 ) ); + } + _setplayermomentum( self, self.pers[ "momentum" ] + score ); +} + +resetplayermomentumondeath() +{ + if ( isDefined( level.usingscorestreaks ) && level.usingscorestreaks ) + { + _setplayermomentum( self, 0 ); + self thread resetscorechain(); + } +} + +giveplayermomentum( event, player, victim, weapon, descvalue ) +{ +} + +giveplayerscore( event, player, victim, weapon, descvalue ) +{ + scorediff = 0; + momentum = player.pers[ "momentum" ]; + giveplayermomentum( event, player, victim, weapon, descvalue ); + newmomentum = player.pers[ "momentum" ]; + if ( level.overrideplayerscore ) + { + return 0; + } + pixbeginevent( "level.onPlayerScore" ); + score = player.pers[ "score" ]; + [[ level.onplayerscore ]]( event, player, victim ); + newscore = player.pers[ "score" ]; + pixendevent(); + bbprint( "mpplayerscore", "spawnid %d gametime %d type %s player %s delta %d deltamomentum %d team %s", getplayerspawnid( player ), getTime(), event, player.name, newscore - score, newmomentum - momentum, player.team ); + player maps/mp/_bb::bbaddtostat( "score", newscore - score ); + if ( score == newscore ) + { + return 0; + } + pixbeginevent( "givePlayerScore" ); + recordplayerstats( player, "score", newscore ); + scorediff = newscore - score; + player addplayerstatwithgametype( "score", scorediff ); + if ( isDefined( player.pers[ "lastHighestScore" ] ) && newscore > player.pers[ "lastHighestScore" ] ) + { + player setdstat( "HighestStats", "highest_score", newscore ); + } + pixendevent(); + return scorediff; +} + +default_onplayerscore( event, player, victim ) +{ +} + +_setplayerscore( player, score ) +{ +} + +_getplayerscore( player ) +{ + return player.pers[ "score" ]; +} + +_setplayermomentum( player, momentum ) +{ + momentum = clamp( momentum, 0, 2000 ); + oldmomentum = player.pers[ "momentum" ]; + if ( momentum == oldmomentum ) + { + return; + } + player maps/mp/_bb::bbaddtostat( "momentum", momentum - oldmomentum ); + if ( momentum > oldmomentum ) + { + highestmomentumcost = 0; + numkillstreaks = player.killstreak.size; + killstreaktypearray = []; + } + player.pers[ "momentum" ] = momentum; + player.momentum = player.pers[ "momentum" ]; +} + +_giveplayerkillstreakinternal( player, momentum, oldmomentum, killstreaktypearray ) +{ +} + +setplayermomentumdebug() +{ +/# + setdvar( "sv_momentumPercent", 0 ); + while ( 1 ) + { + wait 1; + momentumpercent = getdvarfloatdefault( "sv_momentumPercent", 0 ); + if ( momentumpercent != 0 ) + { + player = gethostplayer(); + if ( !isDefined( player ) ) + { + return; + } + if ( isDefined( player.killstreak ) ) + { + _setplayermomentum( player, int( 2000 * ( momentumpercent / 100 ) ) ); + } + } +#/ + } +} + +giveteamscore( event, team, player, victim ) +{ + if ( level.overrideteamscore ) + { + return; + } + pixbeginevent( "level.onTeamScore" ); + teamscore = game[ "teamScores" ][ team ]; + [[ level.onteamscore ]]( event, team ); + pixendevent(); + newscore = game[ "teamScores" ][ team ]; + bbprint( "mpteamscores", "gametime %d event %s team %d diff %d score %d", getTime(), event, team, newscore - teamscore, newscore ); + if ( teamscore == newscore ) + { + return; + } + updateteamscores( team ); + thread maps/mp/gametypes_zm/_globallogic::checkscorelimit(); +} + +giveteamscoreforobjective( team, score ) +{ + teamscore = game[ "teamScores" ][ team ]; + onteamscore( score, team ); + newscore = game[ "teamScores" ][ team ]; + bbprint( "mpteamobjscores", "gametime %d team %d diff %d score %d", getTime(), team, newscore - teamscore, newscore ); + if ( teamscore == newscore ) + { + return; + } + updateteamscores( team ); + thread maps/mp/gametypes_zm/_globallogic::checkscorelimit(); +} + +_setteamscore( team, teamscore ) +{ + if ( teamscore == game[ "teamScores" ][ team ] ) + { + return; + } + game[ "teamScores" ][ team ] = teamscore; + updateteamscores( team ); + thread maps/mp/gametypes_zm/_globallogic::checkscorelimit(); +} + +resetteamscores() +{ + while ( isDefined( level.roundscorecarry ) || level.roundscorecarry == 0 && maps/mp/_utility::isfirstround() ) + { + _a591 = level.teams; + _k591 = getFirstArrayKey( _a591 ); + while ( isDefined( _k591 ) ) + { + team = _a591[ _k591 ]; + game[ "teamScores" ][ team ] = 0; + _k591 = getNextArrayKey( _a591, _k591 ); + } + } + maps/mp/gametypes_zm/_globallogic_score::updateallteamscores(); +} + +resetallscores() +{ + resetteamscores(); + resetplayerscores(); +} + +resetplayerscores() +{ + players = level.players; + winner = undefined; + tie = 0; + i = 0; + while ( i < players.size ) + { + if ( isDefined( players[ i ].pers[ "score" ] ) ) + { + _setplayerscore( players[ i ], 0 ); + } + i++; + } +} + +updateteamscores( team ) +{ + setteamscore( team, game[ "teamScores" ][ team ] ); + level thread maps/mp/gametypes_zm/_globallogic::checkteamscorelimitsoon( team ); +} + +updateallteamscores() +{ + _a629 = level.teams; + _k629 = getFirstArrayKey( _a629 ); + while ( isDefined( _k629 ) ) + { + team = _a629[ _k629 ]; + updateteamscores( team ); + _k629 = getNextArrayKey( _a629, _k629 ); + } +} + +_getteamscore( team ) +{ + return game[ "teamScores" ][ team ]; +} + +gethighestteamscoreteam() +{ + score = 0; + winning_teams = []; + _a645 = level.teams; + _k645 = getFirstArrayKey( _a645 ); + while ( isDefined( _k645 ) ) + { + team = _a645[ _k645 ]; + team_score = game[ "teamScores" ][ team ]; + if ( team_score > score ) + { + score = team_score; + winning_teams = []; + } + if ( team_score == score ) + { + winning_teams[ team ] = team; + } + _k645 = getNextArrayKey( _a645, _k645 ); + } + return winning_teams; +} + +areteamarraysequal( teamsa, teamsb ) +{ + if ( teamsa.size != teamsb.size ) + { + return 0; + } + _a668 = teamsa; + _k668 = getFirstArrayKey( _a668 ); + while ( isDefined( _k668 ) ) + { + team = _a668[ _k668 ]; + if ( !isDefined( teamsb[ team ] ) ) + { + return 0; + } + _k668 = getNextArrayKey( _a668, _k668 ); + } + return 1; +} + +onteamscore( score, team ) +{ + game[ "teamScores" ][ team ] += score; + if ( level.scorelimit && game[ "teamScores" ][ team ] > level.scorelimit ) + { + game[ "teamScores" ][ team ] = level.scorelimit; + } + if ( level.splitscreen ) + { + return; + } + if ( level.scorelimit == 1 ) + { + return; + } + iswinning = gethighestteamscoreteam(); + if ( iswinning.size == 0 ) + { + return; + } + if ( ( getTime() - level.laststatustime ) < 5000 ) + { + return; + } + if ( areteamarraysequal( iswinning, level.waswinning ) ) + { + return; + } + level.laststatustime = getTime(); + while ( iswinning.size == 1 ) + { + _a707 = iswinning; + _k707 = getFirstArrayKey( _a707 ); + while ( isDefined( _k707 ) ) + { + team = _a707[ _k707 ]; + if ( isDefined( level.waswinning[ team ] ) ) + { + if ( level.waswinning.size == 1 ) + { + } + } + else + { + maps/mp/gametypes_zm/_globallogic_audio::leaderdialog( "lead_taken", team, "status" ); + } + _k707 = getNextArrayKey( _a707, _k707 ); + } + } + while ( level.waswinning.size == 1 ) + { + _a726 = level.waswinning; + _k726 = getFirstArrayKey( _a726 ); + while ( isDefined( _k726 ) ) + { + team = _a726[ _k726 ]; + if ( isDefined( iswinning[ team ] ) ) + { + if ( iswinning.size == 1 ) + { + } + else if ( level.waswinning.size > 1 ) + { + } + } + else + { + maps/mp/gametypes_zm/_globallogic_audio::leaderdialog( "lead_lost", team, "status" ); + } + _k726 = getNextArrayKey( _a726, _k726 ); + } + } + level.waswinning = iswinning; +} + +default_onteamscore( event, team ) +{ +} + +initpersstat( dataname, record_stats, init_to_stat_value ) +{ + if ( !isDefined( self.pers[ dataname ] ) ) + { + self.pers[ dataname ] = 0; + } + if ( !isDefined( record_stats ) || record_stats == 1 ) + { + recordplayerstats( self, dataname, int( self.pers[ dataname ] ) ); + } + if ( isDefined( init_to_stat_value ) && init_to_stat_value == 1 ) + { + self.pers[ dataname ] = self getdstat( "PlayerStatsList", dataname, "StatValue" ); + } +} + +getpersstat( dataname ) +{ + return self.pers[ dataname ]; +} + +incpersstat( dataname, increment, record_stats, includegametype ) +{ + pixbeginevent( "incPersStat" ); + self.pers[ dataname ] += increment; + if ( isDefined( includegametype ) && includegametype ) + { + self addplayerstatwithgametype( dataname, increment ); + } + else + { + self addplayerstat( dataname, increment ); + } + if ( !isDefined( record_stats ) || record_stats == 1 ) + { + self thread threadedrecordplayerstats( dataname ); + } + pixendevent(); +} + +threadedrecordplayerstats( dataname ) +{ + self endon( "disconnect" ); + waittillframeend; + recordplayerstats( self, dataname, self.pers[ dataname ] ); +} + +updatewinstats( winner ) +{ +} + +updatelossstats( loser ) +{ + loser addplayerstatwithgametype( "losses", 1 ); + loser updatestatratio( "wlratio", "wins", "losses" ); + loser notify( "loss" ); +} + +updatetiestats( loser ) +{ + loser addplayerstatwithgametype( "losses", -1 ); + loser addplayerstatwithgametype( "ties", 1 ); + loser updatestatratio( "wlratio", "wins", "losses" ); + loser setdstat( "playerstatslist", "cur_win_streak", "StatValue", 0 ); + loser notify( "tie" ); +} + +updatewinlossstats( winner ) +{ + if ( !waslastround() && !level.hostforcedend ) + { + return; + } + players = level.players; + if ( !isDefined( winner ) || isDefined( winner ) && !isplayer( winner ) && winner == "tie" ) + { + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ].pers[ "team" ] ) ) + { + i++; + continue; + } + else if ( level.hostforcedend && players[ i ] ishost() ) + { + i++; + continue; + } + else + { + updatetiestats( players[ i ] ); + } + i++; + } + } + else if ( isplayer( winner ) ) + { + if ( level.hostforcedend && winner ishost() ) + { + return; + } + updatewinstats( winner ); + } + else + { + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ].pers[ "team" ] ) ) + { + i++; + continue; + } + else if ( level.hostforcedend && players[ i ] ishost() ) + { + i++; + continue; + } + else + { + if ( winner == "tie" ) + { + updatetiestats( players[ i ] ); + i++; + continue; + } + else if ( players[ i ].pers[ "team" ] == winner ) + { + updatewinstats( players[ i ] ); + i++; + continue; + } + else + { + players[ i ] setdstat( "playerstatslist", "cur_win_streak", "StatValue", 0 ); + } + } + i++; + } + } +} + +backupandclearwinstreaks() +{ +} + +restorewinstreaks( winner ) +{ +} + +inckillstreaktracker( sweapon ) +{ + self endon( "disconnect" ); + waittillframeend; + if ( sweapon == "artillery_mp" ) + { + self.pers[ "artillery_kills" ]++; + } + if ( sweapon == "dog_bite_mp" ) + { + self.pers[ "dog_kills" ]++; + } +} + +trackattackerkill( name, rank, xp, prestige, xuid ) +{ + self endon( "disconnect" ); + attacker = self; + waittillframeend; + pixbeginevent( "trackAttackerKill" ); + if ( !isDefined( attacker.pers[ "killed_players" ][ name ] ) ) + { + attacker.pers[ "killed_players" ][ name ] = 0; + } + if ( !isDefined( attacker.killedplayerscurrent[ name ] ) ) + { + attacker.killedplayerscurrent[ name ] = 0; + } + if ( !isDefined( attacker.pers[ "nemesis_tracking" ][ name ] ) ) + { + attacker.pers[ "nemesis_tracking" ][ name ] = 0; + } + attacker.pers[ "killed_players" ][ name ]++; + attacker.killedplayerscurrent[ name ]++; + attacker.pers[ "nemesis_tracking" ][ name ] += 1; + if ( attacker.pers[ "nemesis_name" ] == name ) + { + attacker maps/mp/_challenges::killednemesis(); + } + if ( attacker.pers[ "nemesis_name" ] == "" || attacker.pers[ "nemesis_tracking" ][ name ] > attacker.pers[ "nemesis_tracking" ][ attacker.pers[ "nemesis_name" ] ] ) + { + attacker.pers[ "nemesis_name" ] = name; + attacker.pers[ "nemesis_rank" ] = rank; + attacker.pers[ "nemesis_rankIcon" ] = prestige; + attacker.pers[ "nemesis_xp" ] = xp; + attacker.pers[ "nemesis_xuid" ] = xuid; + } + else + { + if ( isDefined( attacker.pers[ "nemesis_name" ] ) && attacker.pers[ "nemesis_name" ] == name ) + { + attacker.pers[ "nemesis_rank" ] = rank; + attacker.pers[ "nemesis_xp" ] = xp; + } + } + pixendevent(); +} + +trackattackeedeath( attackername, rank, xp, prestige, xuid ) +{ + self endon( "disconnect" ); + waittillframeend; + pixbeginevent( "trackAttackeeDeath" ); + if ( !isDefined( self.pers[ "killed_by" ][ attackername ] ) ) + { + self.pers[ "killed_by" ][ attackername ] = 0; + } + self.pers[ "killed_by" ][ attackername ]++; + if ( !isDefined( self.pers[ "nemesis_tracking" ][ attackername ] ) ) + { + self.pers[ "nemesis_tracking" ][ attackername ] = 0; + } + self.pers[ "nemesis_tracking" ][ attackername ] += 1,5; + if ( self.pers[ "nemesis_name" ] == "" || self.pers[ "nemesis_tracking" ][ attackername ] > self.pers[ "nemesis_tracking" ][ self.pers[ "nemesis_name" ] ] ) + { + self.pers[ "nemesis_name" ] = attackername; + self.pers[ "nemesis_rank" ] = rank; + self.pers[ "nemesis_rankIcon" ] = prestige; + self.pers[ "nemesis_xp" ] = xp; + self.pers[ "nemesis_xuid" ] = xuid; + } + else + { + if ( isDefined( self.pers[ "nemesis_name" ] ) && self.pers[ "nemesis_name" ] == attackername ) + { + self.pers[ "nemesis_rank" ] = rank; + self.pers[ "nemesis_xp" ] = xp; + } + } + if ( self.pers[ "nemesis_name" ] == attackername && self.pers[ "nemesis_tracking" ][ attackername ] >= 2 ) + { + self setclientuivisibilityflag( "killcam_nemesis", 1 ); + } + else + { + self setclientuivisibilityflag( "killcam_nemesis", 0 ); + } + pixendevent(); +} + +default_iskillboosting() +{ + return 0; +} + +givekillstats( smeansofdeath, sweapon, evictim ) +{ + self endon( "disconnect" ); + waittillframeend; + if ( level.rankedmatch && self [[ level.iskillboosting ]]() ) + { +/# + self iprintlnbold( "GAMETYPE DEBUG: NOT GIVING YOU OFFENSIVE CREDIT AS BOOSTING PREVENTION" ); +#/ + return; + } + pixbeginevent( "giveKillStats" ); + self maps/mp/gametypes_zm/_globallogic_score::incpersstat( "kills", 1, 1, 1 ); + self.kills = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "kills" ); + self updatestatratio( "kdratio", "kills", "deaths" ); + attacker = self; + if ( smeansofdeath == "MOD_HEAD_SHOT" ) + { + attacker thread incpersstat( "headshots", 1, 1, 0 ); + attacker.headshots = attacker.pers[ "headshots" ]; + evictim recordkillmodifier( "headshot" ); + } + pixendevent(); +} + +inctotalkills( team ) +{ + if ( level.teambased && isDefined( level.teams[ team ] ) ) + { + game[ "totalKillsTeam" ][ team ]++; + } + game[ "totalKills" ]++; +} + +setinflictorstat( einflictor, eattacker, sweapon ) +{ + if ( !isDefined( eattacker ) ) + { + return; + } + if ( !isDefined( einflictor ) ) + { + eattacker addweaponstat( sweapon, "hits", 1 ); + return; + } + if ( !isDefined( einflictor.playeraffectedarray ) ) + { + einflictor.playeraffectedarray = []; + } + foundnewplayer = 1; + i = 0; + while ( i < einflictor.playeraffectedarray.size ) + { + if ( einflictor.playeraffectedarray[ i ] == self ) + { + foundnewplayer = 0; + break; + } + else + { + i++; + } + } + if ( foundnewplayer ) + { + einflictor.playeraffectedarray[ einflictor.playeraffectedarray.size ] = self; + if ( sweapon == "concussion_grenade_mp" || sweapon == "tabun_gas_mp" ) + { + eattacker addweaponstat( sweapon, "used", 1 ); + } + eattacker addweaponstat( sweapon, "hits", 1 ); + } +} + +processshieldassist( killedplayer ) +{ + self endon( "disconnect" ); + killedplayer endon( "disconnect" ); + wait 0,05; + maps/mp/gametypes_zm/_globallogic_utils::waittillslowprocessallowed(); + if ( !isDefined( level.teams[ self.pers[ "team" ] ] ) ) + { + return; + } + if ( self.pers[ "team" ] == killedplayer.pers[ "team" ] ) + { + return; + } + if ( !level.teambased ) + { + return; + } + self maps/mp/gametypes_zm/_globallogic_score::incpersstat( "assists", 1, 1, 1 ); + self.assists = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "assists" ); +} + +processassist( killedplayer, damagedone, weapon ) +{ + self endon( "disconnect" ); + killedplayer endon( "disconnect" ); + wait 0,05; + maps/mp/gametypes_zm/_globallogic_utils::waittillslowprocessallowed(); + if ( !isDefined( level.teams[ self.pers[ "team" ] ] ) ) + { + return; + } + if ( self.pers[ "team" ] == killedplayer.pers[ "team" ] ) + { + return; + } + if ( !level.teambased ) + { + return; + } + assist_level = "assist"; + assist_level_value = int( ceil( damagedone / 25 ) ); + if ( assist_level_value < 1 ) + { + assist_level_value = 1; + } + else + { + if ( assist_level_value > 3 ) + { + assist_level_value = 3; + } + } + assist_level = ( assist_level + "_" ) + ( assist_level_value * 25 ); + self maps/mp/gametypes_zm/_globallogic_score::incpersstat( "assists", 1, 1, 1 ); + self.assists = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "assists" ); + switch( weapon ) + { + case "concussion_grenade_mp": + assist_level = "assist_concussion"; + break; + case "flash_grenade_mp": + assist_level = "assist_flash"; + break; + case "emp_grenade_mp": + assist_level = "assist_emp"; + break; + case "proximity_grenade_aoe_mp": + case "proximity_grenade_mp": + assist_level = "assist_proximity"; + break; + } + self maps/mp/_challenges::assisted(); +} + +xpratethread() +{ +/# +#/ +} diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic_spawn.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic_spawn.gsc new file mode 100644 index 0000000..fd882a8 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic_spawn.gsc @@ -0,0 +1,959 @@ +#include maps/mp/gametypes_zm/_spawnlogic; +#include maps/mp/gametypes_zm/_globallogic_defaults; +#include maps/mp/gametypes_zm/_hostmigration; +#include maps/mp/gametypes_zm/_spectating; +#include maps/mp/zombies/_zm_perks; +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/gametypes_zm/_globallogic_ui; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/gametypes_zm/_hud_message; +#include maps/mp/gametypes_zm/_globallogic; +#include maps/mp/gametypes_zm/_globallogic_utils; +#include maps/mp/gametypes_zm/_globallogic_audio; +#include maps/mp/gametypes_zm/_spawning; +#include maps/mp/gametypes_zm/_globallogic_player; +#include maps/mp/_utility; +#include common_scripts/utility; + +timeuntilspawn( includeteamkilldelay ) +{ + if ( level.ingraceperiod && !self.hasspawned ) + { + return 0; + } + respawndelay = 0; + if ( self.hasspawned ) + { + result = self [[ level.onrespawndelay ]](); + if ( isDefined( result ) ) + { + respawndelay = result; + } + else + { + respawndelay = level.playerrespawndelay; + } + if ( includeteamkilldelay && isDefined( self.teamkillpunish ) && self.teamkillpunish ) + { + respawndelay += maps/mp/gametypes_zm/_globallogic_player::teamkilldelay(); + } + } + wavebased = level.waverespawndelay > 0; + if ( wavebased ) + { + return self timeuntilwavespawn( respawndelay ); + } + return respawndelay; +} + +allteamshaveexisted() +{ + _a34 = level.teams; + _k34 = getFirstArrayKey( _a34 ); + while ( isDefined( _k34 ) ) + { + team = _a34[ _k34 ]; + if ( !level.everexisted[ team ] ) + { + return 0; + } + _k34 = getNextArrayKey( _a34, _k34 ); + } + return 1; +} + +mayspawn() +{ + if ( isDefined( level.mayspawn ) && !( self [[ level.mayspawn ]]() ) ) + { + return 0; + } + if ( level.inovertime ) + { + return 0; + } + if ( level.playerqueuedrespawn && !isDefined( self.allowqueuespawn ) && !level.ingraceperiod && !level.usestartspawns ) + { + return 0; + } + if ( level.numlives ) + { + if ( level.teambased ) + { + gamehasstarted = allteamshaveexisted(); + } + else + { + if ( level.maxplayercount > 1 ) + { + if ( !isoneround() ) + { + gamehasstarted = !isfirstround(); + } + } + } + if ( !self.pers[ "lives" ] && gamehasstarted ) + { + return 0; + } + else + { + if ( gamehasstarted ) + { + if ( !level.ingraceperiod && !self.hasspawned && !level.wagermatch ) + { + return 0; + } + } + } + } + return 1; +} + +timeuntilwavespawn( minimumwait ) +{ + earliestspawntime = getTime() + ( minimumwait * 1000 ); + lastwavetime = level.lastwave[ self.pers[ "team" ] ]; + wavedelay = level.wavedelay[ self.pers[ "team" ] ] * 1000; + if ( wavedelay == 0 ) + { + return 0; + } + numwavespassedearliestspawntime = ( earliestspawntime - lastwavetime ) / wavedelay; + numwaves = ceil( numwavespassedearliestspawntime ); + timeofspawn = lastwavetime + ( numwaves * wavedelay ); + if ( isDefined( self.wavespawnindex ) ) + { + timeofspawn += 50 * self.wavespawnindex; + } + return ( timeofspawn - getTime() ) / 1000; +} + +stoppoisoningandflareonspawn() +{ + self endon( "disconnect" ); + self.inpoisonarea = 0; + self.inburnarea = 0; + self.inflarevisionarea = 0; + self.ingroundnapalm = 0; +} + +spawnplayerprediction() +{ + self endon( "disconnect" ); + self endon( "end_respawn" ); + self endon( "game_ended" ); + self endon( "joined_spectators" ); + self endon( "spawned" ); + while ( 1 ) + { + wait 0,5; + if ( isDefined( level.onspawnplayerunified ) && getDvarInt( #"CF6EEB8B" ) == 0 ) + { + maps/mp/gametypes_zm/_spawning::onspawnplayer_unified( 1 ); + continue; + } + else + { + self [[ level.onspawnplayer ]]( 1 ); + } + } +} + +giveloadoutlevelspecific( team, class ) +{ + pixbeginevent( "giveLoadoutLevelSpecific" ); + if ( isDefined( level.givecustomcharacters ) ) + { + self [[ level.givecustomcharacters ]](); + } + if ( isDefined( level.givecustomloadout ) ) + { + self [[ level.givecustomloadout ]](); + } + pixendevent(); +} + +spawnplayer() +{ + pixbeginevent( "spawnPlayer_preUTS" ); + self endon( "disconnect" ); + self endon( "joined_spectators" ); + self notify( "spawned" ); + level notify( "player_spawned" ); + self notify( "end_respawn" ); + self setspawnvariables(); + if ( !self.hasspawned ) + { + self.underscorechance = 70; + self thread maps/mp/gametypes_zm/_globallogic_audio::sndstartmusicsystem(); + } + if ( level.teambased ) + { + self.sessionteam = self.team; + } + else + { + self.sessionteam = "none"; + self.ffateam = self.team; + } + hadspawned = self.hasspawned; + self.sessionstate = "playing"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self.statusicon = ""; + self.damagedplayers = []; + if ( getDvarInt( #"C8077F47" ) > 0 ) + { + self.maxhealth = getDvarInt( #"C8077F47" ); + } + else + { + self.maxhealth = level.playermaxhealth; + } + self.health = self.maxhealth; + self.friendlydamage = undefined; + self.hasspawned = 1; + self.spawntime = getTime(); + self.afk = 0; + if ( self.pers[ "lives" ] || !isDefined( level.takelivesondeath ) && level.takelivesondeath == 0 ) + { + self.pers[ "lives" ]--; + + if ( self.pers[ "lives" ] == 0 ) + { + level notify( "player_eliminated" ); + self notify( "player_eliminated" ); + } + } + self.laststand = undefined; + self.revivingteammate = 0; + self.burning = undefined; + self.nextkillstreakfree = undefined; + self.activeuavs = 0; + self.activecounteruavs = 0; + self.activesatellites = 0; + self.deathmachinekills = 0; + self.disabledweapon = 0; + self resetusability(); + self maps/mp/gametypes_zm/_globallogic_player::resetattackerlist(); + self.diedonvehicle = undefined; + if ( !self.wasaliveatmatchstart ) + { + if ( level.ingraceperiod || maps/mp/gametypes_zm/_globallogic_utils::gettimepassed() < 20000 ) + { + self.wasaliveatmatchstart = 1; + } + } + self setdepthoffield( 0, 0, 512, 512, 4, 0 ); + self resetfov(); + pixbeginevent( "onSpawnPlayer" ); + if ( isDefined( level.onspawnplayerunified ) && getDvarInt( #"CF6EEB8B" ) == 0 ) + { + self [[ level.onspawnplayerunified ]](); + } + else + { + self [[ level.onspawnplayer ]]( 0 ); + } + if ( isDefined( level.playerspawnedcb ) ) + { + self [[ level.playerspawnedcb ]](); + } + pixendevent(); + pixendevent(); + level thread maps/mp/gametypes_zm/_globallogic::updateteamstatus(); + pixbeginevent( "spawnPlayer_postUTS" ); + self thread stoppoisoningandflareonspawn(); + self stopburning(); +/# + assert( maps/mp/gametypes_zm/_globallogic_utils::isvalidclass( self.class ) ); +#/ + self giveloadoutlevelspecific( self.team, self.class ); + if ( level.inprematchperiod ) + { + self freeze_player_controls( 1 ); + team = self.pers[ "team" ]; + if ( isDefined( self.pers[ "music" ].spawn ) && self.pers[ "music" ].spawn == 0 ) + { + if ( level.wagermatch ) + { + music = "SPAWN_WAGER"; + } + else + { + music = game[ "music" ][ "spawn_" + team ]; + } + self thread maps/mp/gametypes_zm/_globallogic_audio::set_music_on_player( music, 0, 0 ); + self.pers[ "music" ].spawn = 1; + } + if ( level.splitscreen ) + { + if ( isDefined( level.playedstartingmusic ) ) + { + music = undefined; + } + else + { + level.playedstartingmusic = 1; + } + } + if ( !isDefined( level.disableprematchmessages ) || level.disableprematchmessages == 0 ) + { + thread maps/mp/gametypes_zm/_hud_message::showinitialfactionpopup( team ); + hintmessage = getobjectivehinttext( self.pers[ "team" ] ); + if ( isDefined( hintmessage ) ) + { + self thread maps/mp/gametypes_zm/_hud_message::hintmessage( hintmessage ); + } + if ( isDefined( game[ "dialog" ][ "gametype" ] ) || !level.splitscreen && self == level.players[ 0 ] ) + { + if ( !isDefined( level.infinalfight ) || !level.infinalfight ) + { + if ( level.hardcoremode ) + { + self maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "gametype_hardcore" ); + } + else + { + self maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "gametype" ); + } + } + } + if ( team == game[ "attackers" ] ) + { + self maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "offense_obj", "introboost" ); + } + else + { + self maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "defense_obj", "introboost" ); + } + } + } + else + { + self freeze_player_controls( 0 ); + self enableweapons(); + if ( !hadspawned && game[ "state" ] == "playing" ) + { + pixbeginevent( "sound" ); + team = self.team; + if ( isDefined( self.pers[ "music" ].spawn ) && self.pers[ "music" ].spawn == 0 ) + { + self thread maps/mp/gametypes_zm/_globallogic_audio::set_music_on_player( "SPAWN_SHORT", 0, 0 ); + self.pers[ "music" ].spawn = 1; + } + if ( level.splitscreen ) + { + if ( isDefined( level.playedstartingmusic ) ) + { + music = undefined; + } + else + { + level.playedstartingmusic = 1; + } + } + if ( !isDefined( level.disableprematchmessages ) || level.disableprematchmessages == 0 ) + { + thread maps/mp/gametypes_zm/_hud_message::showinitialfactionpopup( team ); + hintmessage = getobjectivehinttext( self.pers[ "team" ] ); + if ( isDefined( hintmessage ) ) + { + self thread maps/mp/gametypes_zm/_hud_message::hintmessage( hintmessage ); + } + if ( isDefined( game[ "dialog" ][ "gametype" ] ) || !level.splitscreen && self == level.players[ 0 ] ) + { + if ( !isDefined( level.infinalfight ) || !level.infinalfight ) + { + if ( level.hardcoremode ) + { + self maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "gametype_hardcore" ); + } + else + { + self maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "gametype" ); + } + } + } + if ( team == game[ "attackers" ] ) + { + self maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "offense_obj", "introboost" ); + } + else + { + self maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "defense_obj", "introboost" ); + } + } + pixendevent(); + } + } + if ( getDvar( "scr_showperksonspawn" ) == "" ) + { + setdvar( "scr_showperksonspawn", "0" ); + } + if ( level.hardcoremode ) + { + setdvar( "scr_showperksonspawn", "0" ); + } + if ( !level.splitscreen && getDvarInt( "scr_showperksonspawn" ) == 1 && game[ "state" ] != "postgame" ) + { + pixbeginevent( "showperksonspawn" ); + if ( level.perksenabled == 1 ) + { + self maps/mp/gametypes_zm/_hud_util::showperks(); + } + self thread maps/mp/gametypes_zm/_globallogic_ui::hideloadoutaftertime( 3 ); + self thread maps/mp/gametypes_zm/_globallogic_ui::hideloadoutondeath(); + pixendevent(); + } + if ( isDefined( self.pers[ "momentum" ] ) ) + { + self.momentum = self.pers[ "momentum" ]; + } + pixendevent(); + waittillframeend; + self notify( "spawned_player" ); + self logstring( "S " + self.origin[ 0 ] + " " + self.origin[ 1 ] + " " + self.origin[ 2 ] ); + setdvar( "scr_selecting_location", "" ); +/# + if ( getDvarInt( #"F8D00F60" ) > 0 ) + { + self thread maps/mp/gametypes_zm/_globallogic_score::xpratethread(); +#/ + } + self maps/mp/zombies/_zm_perks::perk_set_max_health_if_jugg( "health_reboot", 1, 0 ); + if ( game[ "state" ] == "postgame" ) + { +/# + assert( !level.intermission ); +#/ + self maps/mp/gametypes_zm/_globallogic_player::freezeplayerforroundend(); + } +} + +spawnspectator( origin, angles ) +{ + self notify( "spawned" ); + self notify( "end_respawn" ); + in_spawnspectator( origin, angles ); +} + +respawn_asspectator( origin, angles ) +{ + in_spawnspectator( origin, angles ); +} + +in_spawnspectator( origin, angles ) +{ + pixmarker( "BEGIN: in_spawnSpectator" ); + self setspawnvariables(); + if ( self.pers[ "team" ] == "spectator" ) + { + self clearlowermessage(); + } + self.sessionstate = "spectator"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self.friendlydamage = undefined; + if ( self.pers[ "team" ] == "spectator" ) + { + self.statusicon = ""; + } + else + { + self.statusicon = "hud_status_dead"; + } + maps/mp/gametypes_zm/_spectating::setspectatepermissionsformachine(); + [[ level.onspawnspectator ]]( origin, angles ); + if ( level.teambased && !level.splitscreen ) + { + self thread spectatorthirdpersonness(); + } + level thread maps/mp/gametypes_zm/_globallogic::updateteamstatus(); + pixmarker( "END: in_spawnSpectator" ); +} + +spectatorthirdpersonness() +{ + self endon( "disconnect" ); + self endon( "spawned" ); + self notify( "spectator_thirdperson_thread" ); + self endon( "spectator_thirdperson_thread" ); + self.spectatingthirdperson = 0; +} + +forcespawn( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "spawned" ); + if ( !isDefined( time ) ) + { + time = 60; + } + wait time; + if ( self.hasspawned ) + { + return; + } + if ( self.pers[ "team" ] == "spectator" ) + { + return; + } + if ( !maps/mp/gametypes_zm/_globallogic_utils::isvalidclass( self.pers[ "class" ] ) ) + { + self.pers[ "class" ] = "CLASS_CUSTOM1"; + self.class = self.pers[ "class" ]; + } + self maps/mp/gametypes_zm/_globallogic_ui::closemenus(); + self thread [[ level.spawnclient ]](); +} + +kickifdontspawn() +{ +/# + if ( getDvarInt( "scr_hostmigrationtest" ) == 1 ) + { + return; +#/ + } + if ( self ishost() ) + { + return; + } + self kickifidontspawninternal(); +} + +kickifidontspawninternal() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "spawned" ); + waittime = 90; + if ( getDvar( #"4257CF5C" ) != "" ) + { + waittime = getDvarFloat( #"4257CF5C" ); + } + mintime = 45; + if ( getDvar( #"0DF057E0" ) != "" ) + { + mintime = getDvarFloat( #"0DF057E0" ); + } + starttime = getTime(); + kickwait( waittime ); + timepassed = ( getTime() - starttime ) / 1000; + if ( timepassed < ( waittime - 0,1 ) && timepassed < mintime ) + { + return; + } + if ( self.hasspawned ) + { + return; + } + if ( sessionmodeisprivate() ) + { + return; + } + if ( self.pers[ "team" ] == "spectator" ) + { + return; + } + kick( self getentitynumber() ); +} + +kickwait( waittime ) +{ + level endon( "game_ended" ); + maps/mp/gametypes_zm/_hostmigration::waitlongdurationwithhostmigrationpause( waittime ); +} + +spawninterroundintermission() +{ + self notify( "spawned" ); + self notify( "end_respawn" ); + self setspawnvariables(); + self clearlowermessage(); + self freeze_player_controls( 0 ); + self.sessionstate = "spectator"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self.friendlydamage = undefined; + self maps/mp/gametypes_zm/_globallogic_defaults::default_onspawnintermission(); + self setorigin( self.origin ); + self setplayerangles( self.angles ); + self setdepthoffield( 0, 128, 512, 4000, 6, 1,8 ); +} + +spawnintermission( usedefaultcallback ) +{ + self notify( "spawned" ); + self notify( "end_respawn" ); + self endon( "disconnect" ); + self setspawnvariables(); + self clearlowermessage(); + self freeze_player_controls( 0 ); + if ( level.rankedmatch && waslastround() ) + { + if ( !self.postgamemilestones || self.postgamecontracts && self.postgamepromotion ) + { + if ( self.postgamepromotion ) + { + self playlocalsound( "mus_level_up" ); + } + else if ( self.postgamecontracts ) + { + self playlocalsound( "mus_challenge_complete" ); + } + else + { + if ( self.postgamemilestones ) + { + self playlocalsound( "mus_contract_complete" ); + } + } + self closeingamemenu(); + self openmenu( game[ "menu_endgameupdate" ] ); + waittime = 4; + while ( waittime ) + { + wait 0,25; + waittime -= 0,25; + self openmenu( game[ "menu_endgameupdate" ] ); + } + self closemenu(); + } + } + self.sessionstate = "intermission"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self.friendlydamage = undefined; + if ( isDefined( usedefaultcallback ) && usedefaultcallback ) + { + maps/mp/gametypes_zm/_globallogic_defaults::default_onspawnintermission(); + } + else + { + [[ level.onspawnintermission ]](); + } + self setdepthoffield( 0, 128, 512, 4000, 6, 1,8 ); +} + +spawnqueuedclientonteam( team ) +{ + player_to_spawn = undefined; + i = 0; + while ( i < level.deadplayers[ team ].size ) + { + player = level.deadplayers[ team ][ i ]; + if ( player.waitingtospawn ) + { + i++; + continue; + } + else + { + player_to_spawn = player; + break; + } + i++; + } + if ( isDefined( player_to_spawn ) ) + { + player_to_spawn.allowqueuespawn = 1; + player_to_spawn maps/mp/gametypes_zm/_globallogic_ui::closemenus(); + player_to_spawn thread [[ level.spawnclient ]](); + } +} + +spawnqueuedclient( dead_player_team, killer ) +{ + if ( !level.playerqueuedrespawn ) + { + return; + } + maps/mp/gametypes_zm/_globallogic_utils::waittillslowprocessallowed(); + spawn_team = undefined; + if ( isDefined( killer ) && isDefined( killer.team ) && isDefined( level.teams[ killer.team ] ) ) + { + spawn_team = killer.team; + } + if ( isDefined( spawn_team ) ) + { + spawnqueuedclientonteam( spawn_team ); + return; + } + _a746 = level.teams; + _k746 = getFirstArrayKey( _a746 ); + while ( isDefined( _k746 ) ) + { + team = _a746[ _k746 ]; + if ( team == dead_player_team ) + { + } + else + { + spawnqueuedclientonteam( team ); + } + _k746 = getNextArrayKey( _a746, _k746 ); + } +} + +allteamsnearscorelimit() +{ + if ( !level.teambased ) + { + return 0; + } + if ( level.scorelimit <= 1 ) + { + return 0; + } + _a763 = level.teams; + _k763 = getFirstArrayKey( _a763 ); + while ( isDefined( _k763 ) ) + { + team = _a763[ _k763 ]; + if ( ( level.scorelimit - 1 ) < game[ "teamScores" ][ team ] ) + { + return 0; + } + _k763 = getNextArrayKey( _a763, _k763 ); + } + return 1; +} + +shouldshowrespawnmessage() +{ + if ( waslastround() ) + { + return 0; + } + if ( isoneround() ) + { + return 0; + } + if ( isDefined( level.livesdonotreset ) && level.livesdonotreset ) + { + return 0; + } + if ( allteamsnearscorelimit() ) + { + return 0; + } + return 1; +} + +default_spawnmessage() +{ + setlowermessage( game[ "strings" ][ "spawn_next_round" ] ); + self thread maps/mp/gametypes_zm/_globallogic_ui::removespawnmessageshortly( 3 ); +} + +showspawnmessage() +{ + if ( shouldshowrespawnmessage() ) + { + self thread [[ level.spawnmessage ]](); + } +} + +spawnclient( timealreadypassed ) +{ + pixbeginevent( "spawnClient" ); +/# + assert( isDefined( self.team ) ); +#/ +/# + assert( maps/mp/gametypes_zm/_globallogic_utils::isvalidclass( self.class ) ); +#/ + if ( !self mayspawn() ) + { + currentorigin = self.origin; + currentangles = self.angles; + self showspawnmessage(); + self thread [[ level.spawnspectator ]]( currentorigin + vectorScale( ( 0, 0, 1 ), 60 ), currentangles ); + pixendevent(); + return; + } + if ( self.waitingtospawn ) + { + pixendevent(); + return; + } + self.waitingtospawn = 1; + self.allowqueuespawn = undefined; + self waitandspawnclient( timealreadypassed ); + if ( isDefined( self ) ) + { + self.waitingtospawn = 0; + } + pixendevent(); +} + +waitandspawnclient( timealreadypassed ) +{ + self endon( "disconnect" ); + self endon( "end_respawn" ); + level endon( "game_ended" ); + if ( !isDefined( timealreadypassed ) ) + { + timealreadypassed = 0; + } + spawnedasspectator = 0; + if ( isDefined( self.teamkillpunish ) && self.teamkillpunish ) + { + teamkilldelay = maps/mp/gametypes_zm/_globallogic_player::teamkilldelay(); + if ( teamkilldelay > timealreadypassed ) + { + teamkilldelay -= timealreadypassed; + timealreadypassed = 0; + } + else + { + timealreadypassed -= teamkilldelay; + teamkilldelay = 0; + } + if ( teamkilldelay > 0 ) + { + setlowermessage( &"MP_FRIENDLY_FIRE_WILL_NOT", teamkilldelay ); + self thread respawn_asspectator( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), self.angles ); + spawnedasspectator = 1; + wait teamkilldelay; + } + self.teamkillpunish = 0; + } + if ( !isDefined( self.wavespawnindex ) && isDefined( level.waveplayerspawnindex[ self.team ] ) ) + { + self.wavespawnindex = level.waveplayerspawnindex[ self.team ]; + level.waveplayerspawnindex[ self.team ]++; + } + timeuntilspawn = timeuntilspawn( 0 ); + if ( timeuntilspawn > timealreadypassed ) + { + timeuntilspawn -= timealreadypassed; + timealreadypassed = 0; + } + else + { + timealreadypassed -= timeuntilspawn; + timeuntilspawn = 0; + } + if ( timeuntilspawn > 0 ) + { + if ( level.playerqueuedrespawn ) + { + setlowermessage( game[ "strings" ][ "you_will_spawn" ], timeuntilspawn ); + } + else if ( self issplitscreen() ) + { + setlowermessage( game[ "strings" ][ "waiting_to_spawn_ss" ], timeuntilspawn, 1 ); + } + else + { + setlowermessage( game[ "strings" ][ "waiting_to_spawn" ], timeuntilspawn ); + } + if ( !spawnedasspectator ) + { + spawnorigin = self.origin + vectorScale( ( 0, 0, 1 ), 60 ); + spawnangles = self.angles; + if ( isDefined( level.useintermissionpointsonwavespawn ) && [[ level.useintermissionpointsonwavespawn ]]() == 1 ) + { + spawnpoint = maps/mp/gametypes_zm/_spawnlogic::getrandomintermissionpoint(); + if ( isDefined( spawnpoint ) ) + { + spawnorigin = spawnpoint.origin; + spawnangles = spawnpoint.angles; + } + } + self thread respawn_asspectator( spawnorigin, spawnangles ); + } + spawnedasspectator = 1; + self maps/mp/gametypes_zm/_globallogic_utils::waitfortimeornotify( timeuntilspawn, "force_spawn" ); + self notify( "stop_wait_safe_spawn_button" ); + } + wavebased = level.waverespawndelay > 0; + if ( !level.playerforcerespawn && self.hasspawned && !wavebased && !self.wantsafespawn && !level.playerqueuedrespawn ) + { + setlowermessage( game[ "strings" ][ "press_to_spawn" ] ); + if ( !spawnedasspectator ) + { + self thread respawn_asspectator( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), self.angles ); + } + spawnedasspectator = 1; + self waitrespawnorsafespawnbutton(); + } + self.waitingtospawn = 0; + self clearlowermessage(); + self.wavespawnindex = undefined; + self.respawntimerstarttime = undefined; + self thread [[ level.spawnplayer ]](); +} + +waitrespawnorsafespawnbutton() +{ + self endon( "disconnect" ); + self endon( "end_respawn" ); + while ( 1 ) + { + if ( self usebuttonpressed() ) + { + return; + } + else + { + wait 0,05; + } + } +} + +waitinspawnqueue() +{ + self endon( "disconnect" ); + self endon( "end_respawn" ); + if ( !level.ingraceperiod && !level.usestartspawns ) + { + currentorigin = self.origin; + currentangles = self.angles; + self thread [[ level.spawnspectator ]]( currentorigin + vectorScale( ( 0, 0, 1 ), 60 ), currentangles ); + self waittill( "queue_respawn" ); + } +} + +setthirdperson( value ) +{ + if ( !level.console ) + { + return; + } + if ( !isDefined( self.spectatingthirdperson ) || value != self.spectatingthirdperson ) + { + self.spectatingthirdperson = value; + if ( value ) + { + self setclientthirdperson( 1 ); + self setdepthoffield( 0, 128, 512, 4000, 6, 1,8 ); + } + else + { + self setclientthirdperson( 0 ); + self setdepthoffield( 0, 0, 512, 4000, 4, 0 ); + } + self resetfov(); + } +} + +setspawnvariables() +{ + resettimeout(); + self stopshellshock(); + self stoprumble( "damage_heavy" ); +} diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic_ui.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic_ui.gsc new file mode 100644 index 0000000..00d91fe --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic_ui.gsc @@ -0,0 +1,544 @@ +#include maps/mp/gametypes_zm/_globallogic_player; +#include maps/mp/gametypes_zm/_spectating; +#include maps/mp/gametypes_zm/_globallogic; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/_utility; + +init() +{ + precachestring( &"MP_HALFTIME" ); + precachestring( &"MP_OVERTIME" ); + precachestring( &"MP_ROUNDEND" ); + precachestring( &"MP_INTERMISSION" ); + precachestring( &"MP_SWITCHING_SIDES_CAPS" ); + precachestring( &"MP_FRIENDLY_FIRE_WILL_NOT" ); + precachestring( &"MP_RAMPAGE" ); + precachestring( &"medal_received" ); + precachestring( &"killstreak_received" ); + precachestring( &"prox_grenade_notify" ); + precachestring( &"player_callout" ); + precachestring( &"score_event" ); + precachestring( &"rank_up" ); + precachestring( &"gun_level_complete" ); + precachestring( &"challenge_complete" ); + if ( sessionmodeiszombiesgame() ) + { + precachestring( &"hud_update_survival_team" ); + } + if ( level.splitscreen ) + { + precachestring( &"MP_ENDED_GAME" ); + } + else + { + precachestring( &"MP_HOST_ENDED_GAME" ); + } +} + +setupcallbacks() +{ + level.autoassign = ::menuautoassign; + level.spectator = ::menuspectator; + level.class = ::menuclass; + level.teammenu = ::menuteam; +} + +hideloadoutaftertime( delay ) +{ + self endon( "disconnect" ); + self endon( "perks_hidden" ); + wait delay; + self thread hideallperks( 0,4 ); + self notify( "perks_hidden" ); +} + +hideloadoutondeath() +{ + self endon( "disconnect" ); + self endon( "perks_hidden" ); + self waittill( "death" ); + self hideallperks(); + self notify( "perks_hidden" ); +} + +hideloadoutonkill() +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "perks_hidden" ); + self waittill( "killed_player" ); + self hideallperks(); + self notify( "perks_hidden" ); +} + +freegameplayhudelems() +{ + while ( isDefined( self.perkicon ) ) + { + numspecialties = 0; + while ( numspecialties < level.maxspecialties ) + { + if ( isDefined( self.perkicon[ numspecialties ] ) ) + { + self.perkicon[ numspecialties ] destroyelem(); + self.perkname[ numspecialties ] destroyelem(); + } + numspecialties++; + } + } + if ( isDefined( self.perkhudelem ) ) + { + self.perkhudelem destroyelem(); + } + if ( isDefined( self.killstreakicon ) ) + { + if ( isDefined( self.killstreakicon[ 0 ] ) ) + { + self.killstreakicon[ 0 ] destroyelem(); + } + if ( isDefined( self.killstreakicon[ 1 ] ) ) + { + self.killstreakicon[ 1 ] destroyelem(); + } + if ( isDefined( self.killstreakicon[ 2 ] ) ) + { + self.killstreakicon[ 2 ] destroyelem(); + } + if ( isDefined( self.killstreakicon[ 3 ] ) ) + { + self.killstreakicon[ 3 ] destroyelem(); + } + if ( isDefined( self.killstreakicon[ 4 ] ) ) + { + self.killstreakicon[ 4 ] destroyelem(); + } + } + self notify( "perks_hidden" ); + if ( isDefined( self.lowermessage ) ) + { + self.lowermessage destroyelem(); + } + if ( isDefined( self.lowertimer ) ) + { + self.lowertimer destroyelem(); + } + if ( isDefined( self.proxbar ) ) + { + self.proxbar destroyelem(); + } + if ( isDefined( self.proxbartext ) ) + { + self.proxbartext destroyelem(); + } + if ( isDefined( self.carryicon ) ) + { + self.carryicon destroyelem(); + } +} + +teamplayercountsequal( playercounts ) +{ + count = undefined; + _a150 = level.teams; + _k150 = getFirstArrayKey( _a150 ); + while ( isDefined( _k150 ) ) + { + team = _a150[ _k150 ]; + if ( !isDefined( count ) ) + { + count = playercounts[ team ]; + } + else + { + if ( count != playercounts[ team ] ) + { + return 0; + } + } + _k150 = getNextArrayKey( _a150, _k150 ); + } + return 1; +} + +teamwithlowestplayercount( playercounts, ignore_team ) +{ + count = 9999; + lowest_team = undefined; + _a169 = level.teams; + _k169 = getFirstArrayKey( _a169 ); + while ( isDefined( _k169 ) ) + { + team = _a169[ _k169 ]; + if ( count > playercounts[ team ] ) + { + count = playercounts[ team ]; + lowest_team = team; + } + _k169 = getNextArrayKey( _a169, _k169 ); + } + return lowest_team; +} + +menuautoassign( comingfrommenu ) +{ + teamkeys = getarraykeys( level.teams ); + assignment = teamkeys[ randomint( teamkeys.size ) ]; + self closemenus(); + if ( isDefined( level.forceallallies ) && level.forceallallies ) + { + assignment = "allies"; + } + else + { + if ( level.teambased ) + { + if ( getDvarInt( "party_autoteams" ) == 1 ) + { + if ( level.allow_teamchange == "1" || self.hasspawned && comingfrommenu ) + { + assignment = ""; + break; + } + else + { + team = getassignedteam( self ); + switch( team ) + { + case 1: + assignment = teamkeys[ 1 ]; + break; + case 2: + assignment = teamkeys[ 0 ]; + break; + case 3: + assignment = teamkeys[ 2 ]; + break; + case 4: + if ( !isDefined( level.forceautoassign ) || !level.forceautoassign ) + { + self setclientscriptmainmenu( game[ "menu_class" ] ); + return; + } + default: + assignment = ""; + if ( isDefined( level.teams[ team ] ) ) + { + assignment = team; + } + else + { + if ( team == "spectator" && !level.forceautoassign ) + { + self setclientscriptmainmenu( game[ "menu_class" ] ); + return; + } + } + } + } + } + if ( assignment == "" || getDvarInt( "party_autoteams" ) == 0 ) + { + if ( sessionmodeiszombiesgame() ) + { + assignment = "allies"; + } + } + if ( assignment == self.pers[ "team" ] || self.sessionstate == "playing" && self.sessionstate == "dead" ) + { + self beginclasschoice(); + return; + } + } + else if ( getDvarInt( "party_autoteams" ) == 1 ) + { + if ( level.allow_teamchange != "1" || !self.hasspawned && !comingfrommenu ) + { + team = getassignedteam( self ); + if ( isDefined( level.teams[ team ] ) ) + { + assignment = team; + } + else + { + if ( team == "spectator" && !level.forceautoassign ) + { + self setclientscriptmainmenu( game[ "menu_class" ] ); + return; + } + } + } + } + } + if ( assignment != self.pers[ "team" ] || self.sessionstate == "playing" && self.sessionstate == "dead" ) + { + self.switching_teams = 1; + self.joining_team = assignment; + self.leaving_team = self.pers[ "team" ]; + self suicide(); + } + self.pers[ "team" ] = assignment; + self.team = assignment; + self.class = undefined; + self updateobjectivetext(); + if ( level.teambased ) + { + self.sessionteam = assignment; + } + else + { + self.sessionteam = "none"; + self.ffateam = assignment; + } + if ( !isalive( self ) ) + { + self.statusicon = "hud_status_dead"; + } + self notify( "joined_team" ); + level notify( "joined_team" ); + self notify( "end_respawn" ); + self beginclasschoice(); + self setclientscriptmainmenu( game[ "menu_class" ] ); +} + +teamscoresequal() +{ + score = undefined; + _a413 = level.teams; + _k413 = getFirstArrayKey( _a413 ); + while ( isDefined( _k413 ) ) + { + team = _a413[ _k413 ]; + if ( !isDefined( score ) ) + { + score = getteamscore( team ); + } + else + { + if ( score != getteamscore( team ) ) + { + return 0; + } + } + _k413 = getNextArrayKey( _a413, _k413 ); + } + return 1; +} + +teamwithlowestscore() +{ + score = 99999999; + lowest_team = undefined; + _a432 = level.teams; + _k432 = getFirstArrayKey( _a432 ); + while ( isDefined( _k432 ) ) + { + team = _a432[ _k432 ]; + if ( score > getteamscore( team ) ) + { + lowest_team = team; + } + _k432 = getNextArrayKey( _a432, _k432 ); + } + return lowest_team; +} + +pickteamfromscores( teams ) +{ + assignment = "allies"; + if ( teamscoresequal() ) + { + assignment = teams[ randomint( teams.size ) ]; + } + else + { + assignment = teamwithlowestscore(); + } + return assignment; +} + +getsplitscreenteam() +{ + index = 0; + while ( index < level.players.size ) + { + if ( !isDefined( level.players[ index ] ) ) + { + index++; + continue; + } + else if ( level.players[ index ] == self ) + { + index++; + continue; + } + else if ( !self isplayeronsamemachine( level.players[ index ] ) ) + { + index++; + continue; + } + else + { + team = level.players[ index ].sessionteam; + if ( team != "spectator" ) + { + return team; + } + } + index++; + } + return ""; +} + +updateobjectivetext() +{ + if ( sessionmodeiszombiesgame() || self.pers[ "team" ] == "spectator" ) + { + self setclientcgobjectivetext( "" ); + return; + } + if ( level.scorelimit > 0 ) + { + self setclientcgobjectivetext( getobjectivescoretext( self.pers[ "team" ] ) ); + } + else + { + self setclientcgobjectivetext( getobjectivetext( self.pers[ "team" ] ) ); + } +} + +closemenus() +{ + self closemenu(); + self closeingamemenu(); +} + +beginclasschoice( forcenewchoice ) +{ +/# + assert( isDefined( level.teams[ self.pers[ "team" ] ] ) ); +#/ + team = self.pers[ "team" ]; + if ( level.disablecac == 1 ) + { + self.pers[ "class" ] = level.defaultclass; + self.class = level.defaultclass; + if ( self.sessionstate != "playing" && game[ "state" ] == "playing" ) + { + self thread [[ level.spawnclient ]](); + } + level thread maps/mp/gametypes_zm/_globallogic::updateteamstatus(); + self thread maps/mp/gametypes_zm/_spectating::setspectatepermissionsformachine(); + return; + } + if ( level.wagermatch ) + { + self openmenu( game[ "menu_changeclass_wager" ] ); + } + else if ( getDvarInt( "barebones_class_mode" ) ) + { + self openmenu( game[ "menu_changeclass_barebones" ] ); + } + else + { + self openmenu( game[ "menu_changeclass_" + team ] ); + } +} + +showmainmenuforteam() +{ +/# + assert( isDefined( level.teams[ self.pers[ "team" ] ] ) ); +#/ + team = self.pers[ "team" ]; + if ( level.wagermatch ) + { + self openmenu( game[ "menu_changeclass_wager" ] ); + } + else + { + self openmenu( game[ "menu_changeclass_" + team ] ); + } +} + +menuteam( team ) +{ + self closemenus(); + if ( !level.console && level.allow_teamchange == "0" && isDefined( self.hasdonecombat ) && self.hasdonecombat ) + { + return; + } + if ( self.pers[ "team" ] != team ) + { + if ( level.ingraceperiod || !isDefined( self.hasdonecombat ) && !self.hasdonecombat ) + { + self.hasspawned = 0; + } + if ( self.sessionstate == "playing" ) + { + self.switching_teams = 1; + self.joining_team = team; + self.leaving_team = self.pers[ "team" ]; + self suicide(); + } + self.pers[ "team" ] = team; + self.team = team; + self.class = undefined; + self updateobjectivetext(); + if ( level.teambased ) + { + self.sessionteam = team; + } + else + { + self.sessionteam = "none"; + self.ffateam = team; + } + self setclientscriptmainmenu( game[ "menu_class" ] ); + self notify( "joined_team" ); + level notify( "joined_team" ); + self notify( "end_respawn" ); + } + self beginclasschoice(); +} + +menuspectator() +{ + self closemenus(); + if ( self.pers[ "team" ] != "spectator" ) + { + if ( isalive( self ) ) + { + self.switching_teams = 1; + self.joining_team = "spectator"; + self.leaving_team = self.pers[ "team" ]; + self suicide(); + } + self.pers[ "team" ] = "spectator"; + self.team = "spectator"; + self.class = undefined; + self updateobjectivetext(); + self.sessionteam = "spectator"; + if ( !level.teambased ) + { + self.ffateam = "spectator"; + } + [[ level.spawnspectator ]](); + self thread maps/mp/gametypes_zm/_globallogic_player::spectate_player_watcher(); + self setclientscriptmainmenu( game[ "menu_class" ] ); + self notify( "joined_spectators" ); + } +} + +menuclass( response ) +{ + self closemenus(); +} + +removespawnmessageshortly( delay ) +{ + self endon( "disconnect" ); + waittillframeend; + self endon( "end_respawn" ); + wait delay; + self clearlowermessage( 2 ); +} diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic_utils.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic_utils.gsc new file mode 100644 index 0000000..4de74a7 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic_utils.gsc @@ -0,0 +1,478 @@ +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/gametypes_zm/_hostmigration; +#include maps/mp/gametypes_zm/_hud_message; +#include maps/mp/_utility; + +waittillslowprocessallowed() +{ + while ( level.lastslowprocessframe == getTime() ) + { + wait 0,05; + } + level.lastslowprocessframe = getTime(); +} + +testmenu() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + wait 10; + notifydata = spawnstruct(); + notifydata.titletext = &"MP_CHALLENGE_COMPLETED"; + notifydata.notifytext = "wheee"; + notifydata.sound = "mp_challenge_complete"; + self thread maps/mp/gametypes_zm/_hud_message::notifymessage( notifydata ); + } +} + +testshock() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + wait 3; + numshots = randomint( 6 ); + i = 0; + while ( i < numshots ) + { + iprintlnbold( numshots ); + self shellshock( "frag_grenade_mp", 0,2 ); + wait 0,1; + i++; + } + } +} + +testhps() +{ + self endon( "death" ); + self endon( "disconnect" ); + hps = []; + hps[ hps.size ] = "radar_mp"; + hps[ hps.size ] = "artillery_mp"; + hps[ hps.size ] = "dogs_mp"; + for ( ;; ) + { + hp = "radar_mp"; + wait 20; + } +} + +timeuntilroundend() +{ + if ( level.gameended ) + { + timepassed = ( getTime() - level.gameendtime ) / 1000; + timeremaining = level.postroundtime - timepassed; + if ( timeremaining < 0 ) + { + return 0; + } + return timeremaining; + } + if ( level.inovertime ) + { + return undefined; + } + if ( level.timelimit <= 0 ) + { + return undefined; + } + if ( !isDefined( level.starttime ) ) + { + return undefined; + } + timepassed = ( gettimepassed() - level.starttime ) / 1000; + timeremaining = ( level.timelimit * 60 ) - timepassed; + return timeremaining + level.postroundtime; +} + +gettimeremaining() +{ + return ( ( level.timelimit * 60 ) * 1000 ) - gettimepassed(); +} + +registerpostroundevent( eventfunc ) +{ + if ( !isDefined( level.postroundevents ) ) + { + level.postroundevents = []; + } + level.postroundevents[ level.postroundevents.size ] = eventfunc; +} + +executepostroundevents() +{ + if ( !isDefined( level.postroundevents ) ) + { + return; + } + i = 0; + while ( i < level.postroundevents.size ) + { + [[ level.postroundevents[ i ] ]](); + i++; + } +} + +getvalueinrange( value, minvalue, maxvalue ) +{ + if ( value > maxvalue ) + { + return maxvalue; + } + else + { + if ( value < minvalue ) + { + return minvalue; + } + else + { + return value; + } + } +} + +assertproperplacement() +{ +/# + numplayers = level.placement[ "all" ].size; + i = 0; + while ( i < ( numplayers - 1 ) ) + { + if ( isDefined( level.placement[ "all" ][ i ] ) && isDefined( level.placement[ "all" ][ i + 1 ] ) ) + { + if ( level.placement[ "all" ][ i ].score < level.placement[ "all" ][ i + 1 ].score ) + { + println( "^1Placement array:" ); + i = 0; + while ( i < numplayers ) + { + player = level.placement[ "all" ][ i ]; + println( "^1" + i + ". " + player.name + ": " + player.score ); + i++; + } + assertmsg( "Placement array was not properly sorted" ); + return; + } + } + else + { + i++; +#/ + } + } +} + +isvalidclass( class ) +{ + if ( level.oldschool || sessionmodeiszombiesgame() ) + { +/# + assert( !isDefined( class ) ); +#/ + return 1; + } + if ( isDefined( class ) ) + { + return class != ""; + } +} + +playtickingsound( gametype_tick_sound ) +{ + self endon( "death" ); + self endon( "stop_ticking" ); + level endon( "game_ended" ); + time = level.bombtimer; + while ( 1 ) + { + self playsound( gametype_tick_sound ); + if ( time > 10 ) + { + time -= 1; + wait 1; + } + else if ( time > 4 ) + { + time -= 0,5; + wait 0,5; + } + else if ( time > 1 ) + { + time -= 0,4; + wait 0,4; + } + else + { + time -= 0,3; + wait 0,3; + } + maps/mp/gametypes_zm/_hostmigration::waittillhostmigrationdone(); + } +} + +stoptickingsound() +{ + self notify( "stop_ticking" ); +} + +gametimer() +{ + level endon( "game_ended" ); + level waittill( "prematch_over" ); + level.starttime = getTime(); + level.discardtime = 0; + if ( isDefined( game[ "roundMillisecondsAlreadyPassed" ] ) ) + { + level.starttime -= game[ "roundMillisecondsAlreadyPassed" ]; + } + prevtime = getTime(); + while ( game[ "state" ] == "playing" ) + { + if ( !level.timerstopped ) + { + game[ "timepassed" ] += getTime() - prevtime; + } + prevtime = getTime(); + wait 1; + } +} + +gettimepassed() +{ + if ( !isDefined( level.starttime ) ) + { + return 0; + } + if ( level.timerstopped ) + { + return level.timerpausetime - level.starttime - level.discardtime; + } + else + { + return getTime() - level.starttime - level.discardtime; + } +} + +pausetimer() +{ + if ( level.timerstopped ) + { + return; + } + level.timerstopped = 1; + level.timerpausetime = getTime(); +} + +resumetimer() +{ + if ( !level.timerstopped ) + { + return; + } + level.timerstopped = 0; + level.discardtime += getTime() - level.timerpausetime; +} + +getscoreremaining( team ) +{ +/# + if ( !isplayer( self ) ) + { + assert( isDefined( team ) ); + } +#/ + scorelimit = level.scorelimit; + if ( isplayer( self ) ) + { + return scorelimit - maps/mp/gametypes_zm/_globallogic_score::_getplayerscore( self ); + } + else + { + return scorelimit - getteamscore( team ); + } +} + +getscoreperminute( team ) +{ +/# + if ( !isplayer( self ) ) + { + assert( isDefined( team ) ); + } +#/ + scorelimit = level.scorelimit; + timelimit = level.timelimit; + minutespassed = ( gettimepassed() / 60000 ) + 0,0001; + if ( isplayer( self ) ) + { + return maps/mp/gametypes_zm/_globallogic_score::_getplayerscore( self ) / minutespassed; + } + else + { + return getteamscore( team ) / minutespassed; + } +} + +getestimatedtimeuntilscorelimit( team ) +{ +/# + if ( !isplayer( self ) ) + { + assert( isDefined( team ) ); + } +#/ + scoreperminute = self getscoreperminute( team ); + scoreremaining = self getscoreremaining( team ); + if ( !scoreperminute ) + { + return 999999; + } + return scoreremaining / scoreperminute; +} + +rumbler() +{ + self endon( "disconnect" ); + while ( 1 ) + { + wait 0,1; + self playrumbleonentity( "damage_heavy" ); + } +} + +waitfortimeornotify( time, notifyname ) +{ + self endon( notifyname ); + wait time; +} + +waitfortimeornotifynoartillery( time, notifyname ) +{ + self endon( notifyname ); + wait time; + while ( isDefined( level.artilleryinprogress ) ) + { +/# + assert( level.artilleryinprogress ); +#/ + wait 0,25; + } +} + +isheadshot( sweapon, shitloc, smeansofdeath, einflictor ) +{ + if ( shitloc != "head" && shitloc != "helmet" ) + { + return 0; + } + switch( smeansofdeath ) + { + case "MOD_BAYONET": + case "MOD_MELEE": + return 0; + case "MOD_IMPACT": + if ( sweapon != "knife_ballistic_mp" ) + { + return 0; + } + } + return 1; +} + +gethitlocheight( shitloc ) +{ + switch( shitloc ) + { + case "head": + case "helmet": + case "neck": + return 60; + case "gun": + case "left_arm_lower": + case "left_arm_upper": + case "left_hand": + case "right_arm_lower": + case "right_arm_upper": + case "right_hand": + case "torso_upper": + return 48; + case "torso_lower": + return 40; + case "left_leg_upper": + case "right_leg_upper": + return 32; + case "left_leg_lower": + case "right_leg_lower": + return 10; + case "left_foot": + case "right_foot": + return 5; + } + return 48; +} + +debugline( start, end ) +{ +/# + i = 0; + while ( i < 50 ) + { + line( start, end ); + wait 0,05; + i++; +#/ + } +} + +isexcluded( entity, entitylist ) +{ + index = 0; + while ( index < entitylist.size ) + { + if ( entity == entitylist[ index ] ) + { + return 1; + } + index++; + } + return 0; +} + +waitfortimeornotifies( desireddelay ) +{ + startedwaiting = getTime(); + waitedtime = ( getTime() - startedwaiting ) / 1000; + if ( waitedtime < desireddelay ) + { + wait ( desireddelay - waitedtime ); + return desireddelay; + } + else + { + return waitedtime; + } +} + +logteamwinstring( wintype, winner ) +{ + log_string = wintype; + if ( isDefined( winner ) ) + { + log_string = ( log_string + ", win: " ) + winner; + } + _a469 = level.teams; + _k469 = getFirstArrayKey( _a469 ); + while ( isDefined( _k469 ) ) + { + team = _a469[ _k469 ]; + log_string = ( log_string + ", " ) + team + ": " + game[ "teamScores" ][ team ]; + _k469 = getNextArrayKey( _a469, _k469 ); + } + logstring( log_string ); +} diff --git a/patch_zm/maps/mp/gametypes_zm/_globallogic_vehicle.gsc b/patch_zm/maps/mp/gametypes_zm/_globallogic_vehicle.gsc new file mode 100644 index 0000000..9bfb41d --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_globallogic_vehicle.gsc @@ -0,0 +1,471 @@ +#include maps/mp/gametypes_zm/_damagefeedback; +#include maps/mp/gametypes_zm/_globallogic_player; +#include maps/mp/gametypes_zm/_weapons; +#include maps/mp/_utility; + +callback_vehicledamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, damagefromunderneath, modelindex, partname ) +{ + self.idflags = idflags; + self.idflagstime = getTime(); + if ( game[ "state" ] == "postgame" ) + { + return; + } + if ( isDefined( eattacker ) && isplayer( eattacker ) && isDefined( eattacker.candocombat ) && !eattacker.candocombat ) + { + return; + } + if ( !isDefined( vdir ) ) + { + idflags |= level.idflags_no_knockback; + } + friendly = 0; + if ( isDefined( self.maxhealth ) || self.health == self.maxhealth && !isDefined( self.attackers ) ) + { + self.attackers = []; + self.attackerdata = []; + self.attackerdamage = []; + } + if ( sweapon == "none" && isDefined( einflictor ) ) + { + if ( isDefined( einflictor.targetname ) && einflictor.targetname == "explodable_barrel" ) + { + sweapon = "explodable_barrel_mp"; + } + else + { + if ( isDefined( einflictor.destructible_type ) && issubstr( einflictor.destructible_type, "vehicle_" ) ) + { + sweapon = "destructible_car_mp"; + } + } + } + if ( idflags & level.idflags_no_protection ) + { + if ( self isvehicleimmunetodamage( idflags, smeansofdeath, sweapon ) ) + { + return; + } + if ( smeansofdeath == "MOD_PISTOL_BULLET" || smeansofdeath == "MOD_RIFLE_BULLET" ) + { + } + else + { + if ( smeansofdeath == "MOD_PROJECTILE" || smeansofdeath == "MOD_GRENADE" ) + { + idamage *= getvehicleprojectilescalar( sweapon ); + idamage = int( idamage ); + if ( idamage == 0 ) + { + return; + } + } + else + { + if ( smeansofdeath == "MOD_GRENADE_SPLASH" ) + { + idamage *= getvehicleunderneathsplashscalar( sweapon ); + idamage = int( idamage ); + if ( idamage == 0 ) + { + return; + } + } + } + } + idamage *= level.vehicledamagescalar; + idamage = int( idamage ); + if ( isplayer( eattacker ) ) + { + eattacker.pers[ "participation" ]++; + } + prevhealthratio = self.health / self.maxhealth; + if ( isDefined( self.owner ) && isplayer( self.owner ) ) + { + team = self.owner.pers[ "team" ]; + } + if ( level.teambased && isplayer( eattacker ) && team == eattacker.pers[ "team" ] ) + { + if ( level.friendlyfire == 0 ) + { + if ( !allowfriendlyfiredamage( einflictor, eattacker, smeansofdeath, sweapon ) ) + { + return; + } + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishvehicledamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, damagefromunderneath, modelindex, partname, 1 ); + } + else if ( level.friendlyfire == 1 ) + { + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishvehicledamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, damagefromunderneath, modelindex, partname, 0 ); + } + else if ( level.friendlyfire == 2 ) + { + if ( !allowfriendlyfiredamage( einflictor, eattacker, smeansofdeath, sweapon ) ) + { + return; + } + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishvehicledamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, damagefromunderneath, modelindex, partname, 1 ); + } + else + { + if ( level.friendlyfire == 3 ) + { + idamage = int( idamage * 0,5 ); + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishvehicledamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, damagefromunderneath, modelindex, partname, 0 ); + } + } + friendly = 1; + } + else + { + if ( !level.teambased && isDefined( self.targetname ) && self.targetname == "rcbomb" ) + { + } + else + { + if ( isDefined( self.owner ) && isDefined( eattacker ) && self.owner == eattacker ) + { + return; + } + } + if ( idamage < 1 ) + { + idamage = 1; + } + if ( isDefined( eattacker ) && isplayer( eattacker ) && isDefined( sweapon ) ) + { + eattacker thread maps/mp/gametypes_zm/_weapons::checkhit( sweapon ); + } + if ( issubstr( smeansofdeath, "MOD_GRENADE" ) && isDefined( einflictor.iscooked ) ) + { + self.wascooked = getTime(); + } + else + { + self.wascooked = undefined; + } + attacker_seat = undefined; + if ( isDefined( eattacker ) ) + { + attacker_seat = self getoccupantseat( eattacker ); + } + if ( isDefined( eattacker ) ) + { + self.lastdamagewasfromenemy = !isDefined( attacker_seat ); + } + self finishvehicledamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, damagefromunderneath, modelindex, partname, 0 ); + if ( level.gametype == "hack" && sweapon != "emp_grenade_mp" ) + { + idamage = 0; + } + } + if ( isDefined( eattacker ) && eattacker != self ) + { + if ( maps/mp/gametypes_zm/_globallogic_player::dodamagefeedback( sweapon, einflictor ) ) + { + if ( idamage > 0 ) + { + eattacker thread maps/mp/gametypes_zm/_damagefeedback::updatedamagefeedback( smeansofdeath, einflictor ); + } + } + } + } +/# + if ( getDvarInt( "g_debugDamage" ) ) + { + println( "actor:" + self getentitynumber() + " health:" + self.health + " attacker:" + eattacker.clientid + " inflictor is player:" + isplayer( einflictor ) + " damage:" + idamage + " hitLoc:" + shitloc ); +#/ + } + if ( 1 ) + { + lpselfnum = self getentitynumber(); + lpselfteam = ""; + lpattackerteam = ""; + if ( isplayer( eattacker ) ) + { + lpattacknum = eattacker getentitynumber(); + lpattackguid = eattacker getguid(); + lpattackname = eattacker.name; + lpattackerteam = eattacker.pers[ "team" ]; + } + else + { + lpattacknum = -1; + lpattackguid = ""; + lpattackname = ""; + lpattackerteam = "world"; + } + logprint( "VD;" + lpselfnum + ";" + lpselfteam + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sweapon + ";" + idamage + ";" + smeansofdeath + ";" + shitloc + "\n" ); + } +} + +callback_vehicleradiusdamage( einflictor, eattacker, idamage, finnerdamage, fouterdamage, idflags, smeansofdeath, sweapon, vpoint, fradius, fconeanglecos, vconedir, psoffsettime ) +{ + idamage = 0; + finnerdamage = 0; + fouterdamage = 0; + self.idflags = idflags; + self.idflagstime = getTime(); + if ( game[ "state" ] == "postgame" ) + { + return; + } + if ( isDefined( eattacker ) && isplayer( eattacker ) && isDefined( eattacker.candocombat ) && !eattacker.candocombat ) + { + return; + } + friendly = 0; + if ( idflags & level.idflags_no_protection ) + { + if ( self isvehicleimmunetodamage( idflags, smeansofdeath, sweapon ) ) + { + return; + } + if ( smeansofdeath != "MOD_PROJECTILE_SPLASH" || smeansofdeath == "MOD_GRENADE_SPLASH" && smeansofdeath == "MOD_EXPLOSIVE" ) + { + scalar = getvehicleprojectilesplashscalar( sweapon ); + idamage = int( idamage * scalar ); + finnerdamage *= scalar; + fouterdamage *= scalar; + if ( finnerdamage == 0 ) + { + return; + } + if ( idamage < 1 ) + { + idamage = 1; + } + } + occupant_team = undefined; + if ( level.teambased && isplayer( eattacker ) && occupant_team == eattacker.pers[ "team" ] ) + { + if ( level.friendlyfire == 0 ) + { + if ( !allowfriendlyfiredamage( einflictor, eattacker, smeansofdeath, sweapon ) ) + { + return; + } + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishvehicleradiusdamage( einflictor, eattacker, idamage, finnerdamage, fouterdamage, idflags, smeansofdeath, sweapon, vpoint, fradius, fconeanglecos, vconedir, psoffsettime ); + } + else if ( level.friendlyfire == 1 ) + { + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishvehicleradiusdamage( einflictor, eattacker, idamage, finnerdamage, fouterdamage, idflags, smeansofdeath, sweapon, vpoint, fradius, fconeanglecos, vconedir, psoffsettime ); + } + else if ( level.friendlyfire == 2 ) + { + if ( !allowfriendlyfiredamage( einflictor, eattacker, smeansofdeath, sweapon ) ) + { + return; + } + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishvehicleradiusdamage( einflictor, eattacker, idamage, finnerdamage, fouterdamage, idflags, smeansofdeath, sweapon, vpoint, fradius, fconeanglecos, vconedir, psoffsettime ); + } + else + { + if ( level.friendlyfire == 3 ) + { + idamage = int( idamage * 0,5 ); + if ( idamage < 1 ) + { + idamage = 1; + } + self.lastdamagewasfromenemy = 0; + self finishvehicleradiusdamage( einflictor, eattacker, idamage, finnerdamage, fouterdamage, idflags, smeansofdeath, sweapon, vpoint, fradius, fconeanglecos, vconedir, psoffsettime ); + } + } + friendly = 1; + return; + } + else + { + if ( idamage < 1 ) + { + idamage = 1; + } + self finishvehicleradiusdamage( einflictor, eattacker, idamage, finnerdamage, fouterdamage, idflags, smeansofdeath, sweapon, vpoint, fradius, fconeanglecos, vconedir, psoffsettime ); + } + } +} + +vehiclecrush() +{ + self endon( "disconnect" ); + if ( isDefined( level._effect ) && isDefined( level._effect[ "tanksquish" ] ) ) + { + playfx( level._effect[ "tanksquish" ], self.origin + vectorScale( ( 0, 0, 1 ), 30 ) ); + } + self playsound( "chr_crunch" ); +} + +getvehicleprojectilescalar( sweapon ) +{ + if ( sweapon == "satchel_charge_mp" ) + { + scale = 1; + } + else if ( sweapon == "sticky_grenade_mp" ) + { + scale = 1; + } + else if ( sweapon == "claymore_mp" ) + { + scale = 1; + } + else if ( sweapon == "remote_missile_missile_mp" ) + { + scale = 10; + } + else if ( sweapon == "remote_mortar_missile_mp" ) + { + scale = 10; + } + else if ( sweapon == "smaw_mp" ) + { + scale = 0,2; + } + else if ( sweapon == "fhj18_mp" ) + { + scale = 0,2; + } + else if ( issubstr( sweapon, "gl_" ) ) + { + scale = 1; + } + else if ( issubstr( sweapon, "turret_mp" ) ) + { + scale = 1; + } + else if ( issubstr( sweapon, "grenade" ) ) + { + scale = 1; + } + else + { + scale = 1; + } + return scale; +} + +getvehicleprojectilesplashscalar( sweapon ) +{ + if ( sweapon == "satchel_charge_mp" ) + { + scale = 1; + } + else if ( sweapon == "sticky_grenade_mp" ) + { + scale = 1; + } + else if ( sweapon == "claymore_mp" ) + { + scale = 1; + } + else if ( sweapon == "remote_missile_missile_mp" ) + { + scale = 10; + } + else if ( sweapon == "remote_mortar_missile_mp" ) + { + scale = 4; + } + else if ( sweapon == "chopper_minigun_mp" ) + { + scale = 0,5; + } + else if ( issubstr( sweapon, "gl_" ) ) + { + scale = 0,5; + } + else if ( issubstr( sweapon, "turrent_mp" ) ) + { + scale = 0,1; + } + else if ( issubstr( sweapon, "grenade" ) ) + { + scale = 1; + } + else + { + scale = 1; + } + return scale; +} + +getvehicleunderneathsplashscalar( sweapon ) +{ + if ( sweapon == "satchel_charge_mp" ) + { + scale = 10; + scale *= 3; + } + else + { + scale = 1; + } + return scale; +} + +getvehiclebulletdamage( sweapon ) +{ + if ( issubstr( sweapon, "ptrs41_" ) ) + { + idamage = 25; + } + else if ( issubstr( sweapon, "gunner" ) ) + { + idamage = 5; + } + else if ( issubstr( sweapon, "mg42_bipod" ) || issubstr( sweapon, "30cal_bipod" ) ) + { + idamage = 5; + } + else + { + idamage = 1; + } + return idamage; +} + +allowfriendlyfiredamage( einflictor, eattacker, smeansofdeath, sweapon ) +{ + if ( isDefined( self.allowfriendlyfiredamageoverride ) ) + { + return [[ self.allowfriendlyfiredamageoverride ]]( einflictor, eattacker, smeansofdeath, sweapon ); + } + vehicle = eattacker getvehicleoccupied(); + return 0; +} diff --git a/patch_zm/maps/mp/gametypes_zm/_gv_actions.gsc b/patch_zm/maps/mp/gametypes_zm/_gv_actions.gsc new file mode 100644 index 0000000..0b42480 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_gv_actions.gsc @@ -0,0 +1,995 @@ +#include maps/mp/gametypes_zm/_globallogic_ui; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/gametypes_zm/_globallogic; +#include common_scripts/utility; +#include maps/mp/_utility; + +initializeactionarray() +{ + level.gametypeactions = []; + level.gametypeactions[ "GiveAmmo" ] = ::dogiveammo; + level.gametypeactions[ "RemoveAmmo" ] = ::doremoveammo; + level.gametypeactions[ "PlaySound" ] = ::doplaysound; + level.gametypeactions[ "EnableUAV" ] = ::doenableuav; + level.gametypeactions[ "GiveScore" ] = ::dogivescore; + level.gametypeactions[ "RemoveScore" ] = ::doremovescore; + level.gametypeactions[ "SetHeader" ] = ::dosetheader; + level.gametypeactions[ "SetSubHeader" ] = ::dosetsubheader; + level.gametypeactions[ "DisplayMessage" ] = ::dodisplaymessage; + level.gametypeactions[ "GiveHealth" ] = ::dogivehealth; + level.gametypeactions[ "RemoveHealth" ] = ::doremovehealth; + level.gametypeactions[ "SetHealthRegen" ] = ::dosethealthregen; + level.gametypeactions[ "ChangeClass" ] = ::dochangeclass; + level.gametypeactions[ "ChangeTeam" ] = ::dochangeteam; + level.gametypeactions[ "GivePerk" ] = ::dogiveperk; + level.gametypeactions[ "RemovePerk" ] = ::doremoveperk; + level.gametypeactions[ "GiveInvuln" ] = ::dogiveinvuln; + level.gametypeactions[ "RemoveInvuln" ] = ::doremoveinvuln; + level.gametypeactions[ "SetDamageModifier" ] = ::dosetdamagemodifier; + level.gametypeactions[ "GiveKillstreak" ] = ::dogivekillstreak; + level.gametypeactions[ "RemoveKillstreak" ] = ::doremovekillstreak; + level.gametypeactions[ "GiveLives" ] = ::dogivelives; + level.gametypeactions[ "RemoveLives" ] = ::doremovelives; + level.gametypeactions[ "ScaleMoveSpeed" ] = ::doscalemovespeed; + level.gametypeactions[ "ShowOnRadar" ] = ::doshowonradar; + level.conditionals = []; + level.conditionals[ "Equals" ] = ::equals; + level.conditionals[ "==" ] = ::equals; + level.conditionals[ "!=" ] = ::notequals; + level.conditionals[ "<" ] = ::lessthan; + level.conditionals[ "<=" ] = ::lessthanequals; + level.conditionals[ ">" ] = ::greaterthan; + level.conditionals[ ">=" ] = ::greaterthanequals; + level.conditionals[ "InPlace" ] = ::inplace; + level.conditionallefthandside = []; + level.conditionallefthandside[ "PlayersLeft" ] = ::playersleft; + level.conditionallefthandside[ "RoundsPlayed" ] = ::roundsplayed; + level.conditionallefthandside[ "HitBy" ] = ::hitby; + level.conditionallefthandside[ "PlayersClass" ] = ::playersclass; + level.conditionallefthandside[ "VictimsClass" ] = ::playersclass; + level.conditionallefthandside[ "AttackersClass" ] = ::attackersclass; + level.conditionallefthandside[ "PlayersPlace" ] = ::playersplace; + level.conditionallefthandside[ "VictimsPlace" ] = ::playersplace; + level.conditionallefthandside[ "AttackersPlace" ] = ::attackersplace; + level.targets = []; + level.targets[ "Everyone" ] = ::gettargeteveryone; + level.targets[ "PlayersLeft" ] = ::gettargetplayersleft; + level.targets[ "PlayersEliminated" ] = ::gettargetplayerseliminated; + level.targets[ "PlayersTeam" ] = ::gettargetplayersteam; + level.targets[ "VictimsTeam" ] = ::gettargetplayersteam; + level.targets[ "OtherTeam" ] = ::gettargetotherteam; + level.targets[ "AttackersTeam" ] = ::gettargetotherteam; + level.targets[ "PlayersLeftOnPlayersTeam" ] = ::gettargetplayersleftonplayersteam; + level.targets[ "PlayersLeftOnOtherTeam" ] = ::gettargetplayersleftonotherteam; + level.targets[ "PlayersLeftOnVictimsTeam" ] = ::gettargetplayersleftonplayersteam; + level.targets[ "PlayersLeftOnAttackersTeam" ] = ::gettargetplayersleftonotherteam; + level.targets[ "PlayersEliminatedOnPlayersTeam" ] = ::gettargetplayerseliminatedonplayersteam; + level.targets[ "PlayersEliminatedOnOtherTeam" ] = ::gettargetplayerseliminatedonotherteam; + level.targets[ "PlayersEliminatedOnVictimsTeam" ] = ::gettargetplayerseliminatedonplayersteam; + level.targets[ "PlayersEliminatedOnAttackersTeam" ] = ::gettargetplayerseliminatedonotherteam; + level.targets[ "AssistingPlayers" ] = ::getassistingplayers; +} + +equals( param1, param2 ) +{ + return param1 == param2; +} + +notequals( param1, param2 ) +{ + return param1 != param2; +} + +lessthan( param1, param2 ) +{ + return param1 < param2; +} + +lessthanequals( param1, param2 ) +{ + return param1 <= param2; +} + +greaterthan( param1, param2 ) +{ + return param1 > param2; +} + +greaterthanequals( param1, param2 ) +{ + return param1 >= param2; +} + +inplace( param1, param2 ) +{ + if ( param1 == param2 ) + { + return 1; + } + if ( param2 == "top3" && param1 == "first" ) + { + return 1; + } + return 0; +} + +playersleft( rule ) +{ + return 0; +} + +roundsplayed( rule ) +{ + return game[ "roundsplayed" ] + 1; +} + +hitby( rule ) +{ + meansofdeath = rule.target[ "MeansOfDeath" ]; + weapon = rule.target[ "Weapon" ]; + if ( !isDefined( meansofdeath ) || !isDefined( weapon ) ) + { + return undefined; + } + switch( weapon ) + { + case "knife_ballistic_mp": + return "knife"; + } + switch( meansofdeath ) + { + case "MOD_PISTOL_BULLET": + case "MOD_RIFLE_BULLET": + return "bullet"; + case "MOD_BAYONET": + case "MOD_MELEE": + return "knife"; + case "MOD_HEAD_SHOT": + return "headshot"; + case "MOD_EXPLOSIVE": + case "MOD_GRENADE": + case "MOD_GRENADE_SPLASH": + case "MOD_PROJECTILE": + case "MOD_PROJECTILE_SPLASH": + return "explosive"; + } + return undefined; +} + +getplayersclass( player ) +{ + return player.pers[ "class" ]; +} + +playersclass( rule ) +{ + player = rule.target[ "Player" ]; + return getplayersclass( player ); +} + +attackersclass( rule ) +{ + player = rule.target[ "Attacker" ]; + return getplayersclass( player ); +} + +getplayersplace( player ) +{ + maps/mp/gametypes_zm/_globallogic::updateplacement(); + if ( !isDefined( level.placement[ "all" ] ) ) + { + return; + } + place = 0; + while ( place < level.placement[ "all" ].size ) + { + if ( level.placement[ "all" ][ place ] == player ) + { + place++; + continue; + } + else + { + place++; + } + } + place++; + if ( place == 1 ) + { + return "first"; + } + else + { + if ( place <= 3 ) + { + return "top3"; + } + else + { + if ( place == level.placement[ "all" ].size ) + { + return "last"; + } + } + } + return "middle"; +} + +playersplace( rule ) +{ + player = rule.target[ "Player" ]; + return getplayersplace( player ); +} + +attackersplace( rule ) +{ + player = rule.target[ "Attacker" ]; + return getplayersplace( player ); +} + +gettargeteveryone( rule ) +{ + return level.players; +} + +gettargetplayersleft( rule ) +{ + return 0; +} + +gettargetplayerseliminated( rule ) +{ + return 0; +} + +gettargetplayersteam( rule ) +{ + player = rule.target[ "Player" ]; + if ( !isDefined( player ) ) + { + return []; + } + return getplayersonteam( level.players, player.pers[ "team" ] ); +} + +gettargetotherteam( rule ) +{ + player = rule.target[ "Player" ]; + if ( !isDefined( player ) ) + { + return []; + } + return getplayersonteam( level.players, getotherteam( player.pers[ "team" ] ) ); +} + +gettargetplayersleftonplayersteam( rule ) +{ + return []; +} + +gettargetplayersleftonotherteam( rule ) +{ + return []; +} + +gettargetplayerseliminatedonplayersteam( rule ) +{ + return []; +} + +gettargetplayerseliminatedonotherteam( rule ) +{ + return []; +} + +getassistingplayers( rule ) +{ + assisters = []; + attacker = rule.target[ "Attacker" ]; + if ( !isDefined( rule.target[ "Assisters" ] ) || !isDefined( attacker ) ) + { + return assisters; + } + j = 0; + while ( j < rule.target[ "Assisters" ].size ) + { + player = rule.target[ "Assisters" ][ j ]; + if ( !isDefined( player ) ) + { + j++; + continue; + } + else if ( player == attacker ) + { + j++; + continue; + } + else + { + assisters[ assisters.size ] = player; + } + j++; + } + return assisters; +} + +executegametypeeventrule( rule ) +{ + if ( !aregametypeeventruleconditionalsmet( rule ) ) + { + return; + } + if ( !isDefined( level.gametypeactions[ rule.action ] ) ) + { +/# + error( "GAMETYPE VARIANTS - unknown action: " + rule.action + "!" ); +#/ + return; + } + thread internalexecuterule( rule ); +} + +internalexecuterule( rule ) +{ +} + +aregametypeeventruleconditionalsmet( rule ) +{ + if ( !isDefined( rule.conditionals ) || rule.conditionals.size == 0 ) + { + return 1; + } + combinedresult = 1; + if ( rule.conditionaleval == "OR" ) + { + combinedresult = 0; + } + i = 0; + while ( i < rule.conditionals.size ) + { + conditionalresult = evaluategametypeeventruleconditional( rule, rule.conditionals[ i ] ); + switch( rule.conditionaleval ) + { + case "AND": + if ( combinedresult ) + { + combinedresult = conditionalresult; + } + break; + case "OR": + if ( !combinedresult ) + { + combinedresult = conditionalresult; + } + break; + } + if ( rule.conditionaleval == "AND" && !combinedresult ) + { + break; + } + else + { + if ( rule.conditionaleval == "OR" && combinedresult ) + { + break; + } + else + { + i++; + } + } + } + return combinedresult; +} + +evaluategametypeeventruleconditional( rule, conditional ) +{ + if ( isDefined( conditional.lhs ) || !isDefined( conditional.operand ) && !isDefined( conditional.rhs ) ) + { + return 0; + } + if ( !isDefined( level.conditionallefthandside[ conditional.lhs ] ) ) + { + return 0; + } + lhsvalue = [[ level.conditionallefthandside[ conditional.lhs ] ]]( rule ); + if ( !isDefined( lhsvalue ) || !isDefined( level.conditionals[ conditional.operand ] ) ) + { + return 0; + } + return [[ level.conditionals[ conditional.operand ] ]]( lhsvalue, conditional.rhs ); +} + +getplayersonteam( players, team ) +{ + playersonteam = []; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( player.pers[ "team" ] == team ) + { + playersonteam[ playersonteam.size ] = player; + } + i++; + } + return playersonteam; +} + +gettargetsforgametypeeventrule( rule ) +{ + targets = []; + if ( !isDefined( rule.targetname ) ) + { + return targets; + } + if ( isDefined( rule.target[ rule.targetname ] ) ) + { + targets[ targets.size ] = rule.target[ rule.targetname ]; + } + else + { + if ( isDefined( level.targets[ rule.targetname ] ) ) + { + targets = [[ level.targets[ rule.targetname ] ]]( rule ); + } + } + return targets; +} + +doesrulehavevalidparam( rule ) +{ + if ( isDefined( rule.params ) && isarray( rule.params ) ) + { + return rule.params.size > 0; + } +} + +sortplayersbylivesdescending( players ) +{ + if ( !isDefined( players ) ) + { + return undefined; + } + swapped = 1; + n = players.size; + while ( swapped ) + { + swapped = 0; + i = 0; + while ( i < ( n - 1 ) ) + { + if ( players[ i ].pers[ "lives" ] < players[ i + 1 ].pers[ "lives" ] ) + { + temp = players[ i ]; + players[ i ] = players[ i + 1 ]; + players[ i + 1 ] = temp; + swapped = 1; + } + i++; + } + n--; + + } + return players; +} + +giveammo( players, amount ) +{ + i = 0; + while ( i < players.size ) + { + wait 0,5; + player = players[ i ]; + currentweapon = player getcurrentweapon(); + clipammo = player getweaponammoclip( currentweapon ); + player setweaponammoclip( currentweapon, clipammo + amount ); + i++; + } +} + +dogiveammo( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + targets = gettargetsforgametypeeventrule( rule ); + giveammo( targets, rule.params[ 0 ] ); +} + +doremoveammo( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + targets = gettargetsforgametypeeventrule( rule ); + giveammo( targets, 0 - rule.params[ 0 ] ); +} + +doplaysound( rule ) +{ + if ( doesrulehavevalidparam( rule ) ) + { + playsoundonplayers( rule.params[ 0 ] ); + } +} + +doenableuav( rule ) +{ + targets = gettargetsforgametypeeventrule( rule ); + targetindex = 0; + while ( targetindex < targets.size ) + { + targets[ targetindex ].pers[ "hasRadar" ] = 1; + targets[ targetindex ].hasspyplane = 1; + targetindex++; + } +} + +givescore( players, amount ) +{ + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + score = maps/mp/gametypes_zm/_globallogic_score::_getplayerscore( player ); + maps/mp/gametypes_zm/_globallogic_score::_setplayerscore( player, score + amount ); + i++; + } +} + +dogivescore( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + targets = gettargetsforgametypeeventrule( rule ); + givescore( targets, rule.params[ 0 ] ); +} + +doremovescore( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + targets = gettargetsforgametypeeventrule( rule ); + givescore( targets, 0 - rule.params[ 0 ] ); +} + +dosetheader( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + targets = gettargetsforgametypeeventrule( rule ); + targetindex = 0; + while ( targetindex < targets.size ) + { + target = targets[ targetindex ]; + displaytextonhudelem( target, target.customgametypeheader, rule.params[ 0 ], rule.params[ 1 ], "gv_header", rule.params[ 2 ] ); + targetindex++; + } +} + +dosetsubheader( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + targets = gettargetsforgametypeeventrule( rule ); + targetindex = 0; + while ( targetindex < targets.size ) + { + target = targets[ targetindex ]; + displaytextonhudelem( target, target.customgametypesubheader, rule.params[ 0 ], rule.params[ 1 ], "gv_subheader", rule.params[ 2 ] ); + targetindex++; + } +} + +displaytextonhudelem( target, texthudelem, text, secondstodisplay, notifyname, valueparam ) +{ + texthudelem.alpha = 1; + if ( isDefined( valueparam ) ) + { + texthudelem settext( text, valueparam ); + } + else + { + texthudelem settext( text ); + } + if ( !isDefined( secondstodisplay ) || secondstodisplay <= 0 ) + { + target.doingnotify = 0; + target notify( notifyname ); + return; + } + target thread fadecustomgametypehudelem( texthudelem, secondstodisplay, notifyname ); +} + +fadecustomgametypehudelem( hudelem, seconds, notifyname ) +{ + self endon( "disconnect" ); + self notify( notifyname ); + self endon( notifyname ); + if ( seconds <= 0 ) + { + return; + } + self.doingnotify = 1; + wait seconds; + while ( hudelem.alpha > 0 ) + { + hudelem.alpha -= 0,05; + if ( hudelem.alpha < 0 ) + { + hudelem.alpha = 0; + } + wait 0,05; + } + self.doingnotify = 0; +} + +dodisplaymessage( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + targets = gettargetsforgametypeeventrule( rule ); + targetindex = 0; + while ( targetindex < targets.size ) + { + thread announcemessage( targets[ targetindex ], rule.params[ 0 ], 2 ); + targetindex++; + } +} + +announcemessage( target, messagetext, time ) +{ + target endon( "disconnect" ); + clientannouncement( target, messagetext, int( time * 1000 ) ); + if ( time == 0 ) + { + time = getDvarFloat( #"E8C4FC20" ); + } + target.doingnotify = 1; + wait time; + target.doingnotify = 0; +} + +givehealth( players, amount ) +{ + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + player.health += amount; + i++; + } +} + +dogivehealth( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + givehealth( gettargetsforgametypeeventrule( rule ), rule.params[ 0 ] ); +} + +doremovehealth( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + givehealth( gettargetsforgametypeeventrule( rule ), 0 - rule.params[ 0 ] ); +} + +dosethealthregen( rule ) +{ + targets = gettargetsforgametypeeventrule( rule ); + targetindex = 0; + while ( targetindex < targets.size ) + { + player = targets[ targetindex ]; + player.regenrate = rule.params[ 0 ]; + targetindex++; + } +} + +dochangeclass( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } +} + +dochangeteam( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + team = rule.params[ 0 ]; + teamkeys = getarraykeys( level.teams ); + targets = gettargetsforgametypeeventrule( rule ); + targetindex = 0; + while ( targetindex < targets.size ) + { + target = targets[ targetindex ]; + if ( target.pers[ "team" ] == team ) + { + targetindex++; + continue; + } + else + { + while ( team == "toggle" ) + { + team = teamkeys[ randomint( teamkeys.size ) ]; + teamindex = 0; + while ( teamindex < teamkeys.size ) + { + if ( target.pers[ "team" ] == teamkeys[ teamindex ] ) + { + team = teamkeys[ ( teamindex + 1 ) % teamkeys.size ]; + break; + } + else + { + teamindex++; + } + } + } + target.pers[ "team" ] = team; + target.team = team; + if ( level.teambased ) + { + target.sessionteam = team; + } + else + { + target.sessionteam = "none"; + } + target notify( "joined_team" ); + level notify( "joined_team" ); + } + targetindex++; + } +} + +displayperk( player, imagename ) +{ + index = 0; + if ( isDefined( player.perkicon ) ) + { + index = -1; + i = 0; + while ( i < player.perkicon.size ) + { + if ( player.perkicon[ i ].alpha == 0 ) + { + index = i; + break; + } + else + { + i++; + } + } + if ( index == -1 ) + { + return; + } + } + player maps/mp/gametypes_zm/_hud_util::showperk( index, imagename, 10 ); + player thread maps/mp/gametypes_zm/_globallogic_ui::hideloadoutaftertime( 3 ); + player thread maps/mp/gametypes_zm/_globallogic_ui::hideloadoutondeath(); +} + +setorunsetperk( players, perks, shouldset ) +{ + if ( level.perksenabled == 0 ) + { + return; + } + if ( perks.size < 2 ) + { + return; + } + hasperkalready = 0; + imagename = perks[ perks.size - 1 ]; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + perkindex = 0; + while ( perkindex < ( perks.size - 1 ) ) + { + perk = perks[ perkindex ]; + if ( player hasperk( perk ) ) + { + hasperkalready = 1; + } + if ( shouldset ) + { + player setperk( perk ); + perkindex++; + continue; + } + else + { + player unsetperk( perk ); + } + perkindex++; + } + if ( shouldset && !hasperkalready && getDvarInt( "scr_showperksonspawn" ) == 1 ) + { + displayperk( player, imagename ); + } + i++; + } +} + +dogiveperk( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + setorunsetperk( gettargetsforgametypeeventrule( rule ), rule.params, 1 ); +} + +doremoveperk( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + setorunsetperk( gettargetsforgametypeeventrule( rule ), rule.params, 0 ); +} + +giveorremovekillstreak( rule, shouldgive ) +{ +} + +dogivekillstreak( rule ) +{ + giveorremovekillstreak( rule, 1 ); +} + +doremovekillstreak( rule ) +{ + giveorremovekillstreak( rule, 0 ); +} + +givelives( players, amount ) +{ + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + player.pers[ "lives" ] += amount; + if ( player.pers[ "lives" ] < 0 ) + { + player.pers[ "lives" ] = 0; + } + i++; + } +} + +dogivelives( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + givelives( gettargetsforgametypeeventrule( rule ), rule.params[ 0 ] ); +} + +doremovelives( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + givelives( gettargetsforgametypeeventrule( rule ), 0 - rule.params[ 0 ] ); +} + +giveorremoveinvuln( players, shouldgiveinvuln ) +{ + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + i++; + } +} + +dogiveinvuln( rule ) +{ + giveorremoveinvuln( gettargetsforgametypeeventrule( rule ), 1 ); +} + +doremoveinvuln( rule ) +{ + giveorremoveinvuln( gettargetsforgametypeeventrule( rule ), 0 ); +} + +dosetdamagemodifier( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + players = gettargetsforgametypeeventrule( rule ); + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + player.damagemodifier = rule.params[ 0 ]; + i++; + } +} + +doscalemovespeed( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + movespeedscale = rule.params[ 0 ]; + targets = gettargetsforgametypeeventrule( rule ); + targetindex = 0; + while ( targetindex < targets.size ) + { + target = targets[ targetindex ]; + target.movementspeedmodifier = movespeedscale * target getmovespeedscale(); + if ( target.movementspeedmodifier < 0,1 ) + { + target.movementspeedmodifier = 0,1; + } + else + { + if ( target.movementspeedmodifier > 4 ) + { + target.movementspeedmodifier = 4; + } + } + target setmovespeedscale( target.movementspeedmodifier ); + targetindex++; + } +} + +doshowonradar( rule ) +{ + if ( !doesrulehavevalidparam( rule ) ) + { + return; + } + targets = gettargetsforgametypeeventrule( rule ); + targetindex = 0; + while ( targetindex < targets.size ) + { + if ( rule.params[ 0 ] == "enable" ) + { + targets[ targetindex ] setperk( "specialty_showonradar" ); + targetindex++; + continue; + } + else + { + targets[ targetindex ] unsetperk( "specialty_showonradar" ); + } + targetindex++; + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_healthoverlay.gsc b/patch_zm/maps/mp/gametypes_zm/_healthoverlay.gsc new file mode 100644 index 0000000..a7d8f4b --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_healthoverlay.gsc @@ -0,0 +1,288 @@ +#include maps/mp/gametypes_zm/_globallogic_player; + +init() +{ + precacheshader( "overlay_low_health" ); + level.healthoverlaycutoff = 0,55; + regentime = level.playerhealthregentime; + level.playerhealth_regularregendelay = regentime * 1000; + level.healthregendisabled = level.playerhealth_regularregendelay <= 0; + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onplayerspawned(); + player thread onplayerkilled(); + player thread onjoinedteam(); + player thread onjoinedspectators(); + player thread onplayerdisconnect(); + } +} + +onjoinedteam() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_team" ); + self notify( "end_healthregen" ); + } +} + +onjoinedspectators() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_spectators" ); + self notify( "end_healthregen" ); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread playerhealthregen(); + } +} + +onplayerkilled() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "killed_player" ); + self notify( "end_healthregen" ); + } +} + +onplayerdisconnect() +{ + self waittill( "disconnect" ); + self notify( "end_healthregen" ); +} + +playerhealthregen() +{ + self endon( "end_healthregen" ); + if ( self.health <= 0 ) + { +/# + assert( !isalive( self ) ); +#/ + return; + } + maxhealth = self.health; + oldhealth = maxhealth; + player = self; + health_add = 0; + regenrate = 0,1; + usetrueregen = 0; + veryhurt = 0; + player.breathingstoptime = -10000; + thread playerbreathingsound( maxhealth * 0,35 ); + thread playerheartbeatsound( maxhealth * 0,35 ); + lastsoundtime_recover = 0; + hurttime = 0; + newhealth = 0; + for ( ;; ) + { + wait 0,05; + if ( isDefined( player.regenrate ) ) + { + regenrate = player.regenrate; + usetrueregen = 1; + } + if ( player.health == maxhealth ) + { + veryhurt = 0; + self.atbrinkofdeath = 0; + continue; + } + else if ( player.health <= 0 ) + { + return; + } + if ( isDefined( player.laststand ) && player.laststand ) + { + continue; + } + else + { + wasveryhurt = veryhurt; + ratio = player.health / maxhealth; + if ( ratio <= level.healthoverlaycutoff ) + { + veryhurt = 1; + self.atbrinkofdeath = 1; + if ( !wasveryhurt ) + { + hurttime = getTime(); + } + } + if ( player.health >= oldhealth ) + { + regentime = level.playerhealth_regularregendelay; + if ( player hasperk( "specialty_healthregen" ) ) + { + regentime = int( regentime / getDvarFloat( "perk_healthRegenMultiplier" ) ); + } + if ( ( getTime() - hurttime ) < regentime ) + { + break; + } + else if ( level.healthregendisabled ) + { + break; + } + else if ( ( getTime() - lastsoundtime_recover ) > regentime ) + { + lastsoundtime_recover = getTime(); + self notify( "snd_breathing_better" ); + } + if ( veryhurt ) + { + newhealth = ratio; + veryhurttime = 3000; + if ( player hasperk( "specialty_healthregen" ) ) + { + veryhurttime = int( veryhurttime / getDvarFloat( "perk_healthRegenMultiplier" ) ); + } + if ( getTime() > ( hurttime + veryhurttime ) ) + { + newhealth += regenrate; + } + } + else if ( usetrueregen ) + { + newhealth = ratio + regenrate; + } + else + { + newhealth = 1; + } + if ( newhealth >= 1 ) + { + self maps/mp/gametypes_zm/_globallogic_player::resetattackerlist(); + newhealth = 1; + } + if ( newhealth <= 0 ) + { + return; + } + player setnormalhealth( newhealth ); + change = player.health - oldhealth; + if ( change > 0 ) + { + player decayplayerdamages( change ); + } + oldhealth = player.health; + break; + } + else + { + oldhealth = player.health; + health_add = 0; + hurttime = getTime(); + player.breathingstoptime = hurttime + 6000; + } + } + } +} + +decayplayerdamages( decay ) +{ + if ( !isDefined( self.attackerdamage ) ) + { + return; + } + i = 0; + while ( i < self.attackerdamage.size ) + { + if ( !isDefined( self.attackerdamage[ i ] ) || !isDefined( self.attackerdamage[ i ].damage ) ) + { + i++; + continue; + } + else + { + self.attackerdamage[ i ].damage -= decay; + if ( self.attackerdamage[ i ].damage < 0 ) + { + self.attackerdamage[ i ].damage = 0; + } + } + i++; + } +} + +playerbreathingsound( healthcap ) +{ + self endon( "end_healthregen" ); + wait 2; + player = self; + for ( ;; ) + { + wait 0,2; + if ( player.health <= 0 ) + { + return; + } + if ( player.health >= healthcap ) + { + continue; + } + else if ( level.healthregendisabled && getTime() > player.breathingstoptime ) + { + continue; + } + else + { + player notify( "snd_breathing_hurt" ); + wait 0,784; + wait ( 0,1 + randomfloat( 0,8 ) ); + } + } +} + +playerheartbeatsound( healthcap ) +{ + self endon( "end_healthregen" ); + self.hearbeatwait = 0,2; + wait 2; + player = self; + for ( ;; ) + { + wait 0,2; + if ( player.health <= 0 ) + { + return; + } + if ( player.health >= healthcap ) + { + self.hearbeatwait = 0,3; + continue; + } + else if ( level.healthregendisabled && getTime() > player.breathingstoptime ) + { + self.hearbeatwait = 0,3; + continue; + } + else + { + player playlocalsound( "mpl_player_heartbeat" ); + wait self.hearbeatwait; + if ( self.hearbeatwait <= 0,6 ) + { + self.hearbeatwait += 0,1; + } + } + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_hostmigration.gsc b/patch_zm/maps/mp/gametypes_zm/_hostmigration.gsc new file mode 100644 index 0000000..7eca73c --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_hostmigration.gsc @@ -0,0 +1,546 @@ +#include maps/mp/zombies/_zm; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/gametypes_zm/_hud_util; +#include common_scripts/utility; +#include maps/mp/_utility; + +debug_script_structs() +{ +/# + if ( isDefined( level.struct ) ) + { + println( "*** Num structs " + level.struct.size ); + println( "" ); + i = 0; + while ( i < level.struct.size ) + { + struct = level.struct[ i ]; + if ( isDefined( struct.targetname ) ) + { + println( "---" + i + " : " + struct.targetname ); + i++; + continue; + } + else + { + println( "---" + i + " : " + "NONE" ); + } + i++; + } + } + else println( "*** No structs defined." ); +#/ +} + +updatetimerpausedness() +{ + shouldbestopped = isDefined( level.hostmigrationtimer ); + if ( !level.timerstopped && shouldbestopped ) + { + level.timerstopped = 1; + level.timerpausetime = getTime(); + } + else + { + if ( level.timerstopped && !shouldbestopped ) + { + level.timerstopped = 0; + level.discardtime += getTime() - level.timerpausetime; + } + } +} + +callback_hostmigrationsave() +{ +} + +callback_prehostmigrationsave() +{ + undo_link_changes(); + disablezombies( 1 ); + if ( is_true( level._hm_should_pause_spawning ) ) + { + flag_set( "spawn_zombies" ); + } + i = 0; + while ( i < level.players.size ) + { + level.players[ i ] enableinvulnerability(); + i++; + } +} + +pausetimer() +{ + level.migrationtimerpausetime = getTime(); +} + +resumetimer() +{ + level.discardtime += getTime() - level.migrationtimerpausetime; +} + +locktimer() +{ + level endon( "host_migration_begin" ); + level endon( "host_migration_end" ); + for ( ;; ) + { + currtime = getTime(); + wait 0,05; + if ( !level.timerstopped && isDefined( level.discardtime ) ) + { + level.discardtime += getTime() - currtime; + } + } +} + +callback_hostmigration() +{ + redo_link_changes(); + setslowmotion( 1, 1, 0 ); + makedvarserverinfo( "ui_guncycle", 0 ); + level.hostmigrationreturnedplayercount = 0; + if ( level.gameended ) + { +/# + println( "Migration starting at time " + getTime() + ", but game has ended, so no countdown." ); +#/ + return; + } + sethostmigrationstatus( 1 ); + level notify( "host_migration_begin" ); + i = 0; + while ( i < level.players.size ) + { + if ( isDefined( level.hostmigration_link_entity_callback ) ) + { + if ( !isDefined( level.players[ i ]._host_migration_link_entity ) ) + { + level.players[ i ]._host_migration_link_entity = level.players[ i ] [[ level.hostmigration_link_entity_callback ]](); + } + } + level.players[ i ] thread hostmigrationtimerthink(); + i++; + } + while ( isDefined( level.hostmigration_ai_link_entity_callback ) ) + { + zombies = getaiarray( level.zombie_team ); + while ( isDefined( zombies ) && zombies.size > 0 ) + { + _a133 = zombies; + _k133 = getFirstArrayKey( _a133 ); + while ( isDefined( _k133 ) ) + { + zombie = _a133[ _k133 ]; + if ( !isDefined( zombie._host_migration_link_entity ) ) + { + zombie._host_migration_link_entity = zombie [[ level.hostmigration_ai_link_entity_callback ]](); + } + _k133 = getNextArrayKey( _a133, _k133 ); + } + } + } + if ( level.inprematchperiod ) + { + level waittill( "prematch_over" ); + } +/# + println( "Migration starting at time " + getTime() ); +#/ + level.hostmigrationtimer = 1; + thread locktimer(); + zombies = getaiarray( level.zombie_team ); + while ( isDefined( zombies ) && zombies.size > 0 ) + { + _a156 = zombies; + _k156 = getFirstArrayKey( _a156 ); + while ( isDefined( _k156 ) ) + { + zombie = _a156[ _k156 ]; + if ( isDefined( zombie._host_migration_link_entity ) ) + { + ent = spawn( "script_origin", zombie.origin ); + ent.angles = zombie.angles; + zombie linkto( ent ); + ent linkto( zombie._host_migration_link_entity, "tag_origin", zombie._host_migration_link_entity worldtolocalcoords( ent.origin ), ent.angles + zombie._host_migration_link_entity.angles ); + zombie._host_migration_link_helper = ent; + zombie linkto( zombie._host_migration_link_helper ); + } + _k156 = getNextArrayKey( _a156, _k156 ); + } + } + level endon( "host_migration_begin" ); + level._hm_should_pause_spawning = flag( "spawn_zombies" ); + if ( level._hm_should_pause_spawning ) + { + flag_clear( "spawn_zombies" ); + } + hostmigrationwait(); + _a185 = level.players; + _k185 = getFirstArrayKey( _a185 ); + while ( isDefined( _k185 ) ) + { + player = _a185[ _k185 ]; + player thread post_migration_become_vulnerable(); + _k185 = getNextArrayKey( _a185, _k185 ); + } + zombies = getaiarray( level.zombie_team ); + while ( isDefined( zombies ) && zombies.size > 0 ) + { + _a193 = zombies; + _k193 = getFirstArrayKey( _a193 ); + while ( isDefined( _k193 ) ) + { + zombie = _a193[ _k193 ]; + if ( isDefined( zombie._host_migration_link_entity ) ) + { + zombie unlink(); + zombie._host_migration_link_helper delete(); + zombie._host_migration_link_helper = undefined; + zombie._host_migration_link_entity = undefined; + } + _k193 = getNextArrayKey( _a193, _k193 ); + } + } + enablezombies( 1 ); + if ( level._hm_should_pause_spawning ) + { + flag_set( "spawn_zombies" ); + } + level.hostmigrationtimer = undefined; + level._hm_should_pause_spawning = undefined; + sethostmigrationstatus( 0 ); +/# + println( "Migration finished at time " + getTime() ); +#/ + level notify( "host_migration_end" ); +} + +post_migration_become_vulnerable() +{ + self endon( "disconnect" ); + wait 3; + self disableinvulnerability(); +} + +matchstarttimerconsole_internal( counttime, matchstarttimer ) +{ + waittillframeend; + level endon( "match_start_timer_beginning" ); + while ( counttime > 0 && !level.gameended ) + { + matchstarttimer thread maps/mp/gametypes_zm/_hud::fontpulse( level ); + wait ( matchstarttimer.inframes * 0,05 ); + matchstarttimer setvalue( counttime ); + counttime--; + + wait ( 1 - ( matchstarttimer.inframes * 0,05 ) ); + } +} + +matchstarttimerconsole( type, duration ) +{ + level notify( "match_start_timer_beginning" ); + wait 0,05; + matchstarttext = createserverfontstring( "objective", 1,5 ); + matchstarttext setpoint( "CENTER", "CENTER", 0, -40 ); + matchstarttext.sort = 1001; + matchstarttext settext( game[ "strings" ][ "waiting_for_teams" ] ); + matchstarttext.foreground = 0; + matchstarttext.hidewheninmenu = 1; + matchstarttext settext( game[ "strings" ][ type ] ); + matchstarttimer = createserverfontstring( "objective", 2,2 ); + matchstarttimer setpoint( "CENTER", "CENTER", 0, 0 ); + matchstarttimer.sort = 1001; + matchstarttimer.color = ( 1, 1, 0 ); + matchstarttimer.foreground = 0; + matchstarttimer.hidewheninmenu = 1; + matchstarttimer maps/mp/gametypes_zm/_hud::fontpulseinit(); + counttime = int( duration ); + if ( counttime >= 2 ) + { + matchstarttimerconsole_internal( counttime, matchstarttimer ); + } + matchstarttimer destroyelem(); + matchstarttext destroyelem(); +} + +hostmigrationwait() +{ + level endon( "game_ended" ); + if ( level.hostmigrationreturnedplayercount < ( ( level.players.size * 2 ) / 3 ) ) + { + thread matchstarttimerconsole( "waiting_for_teams", 20 ); + hostmigrationwaitforplayers(); + } + thread matchstarttimerconsole( "match_starting_in", 5 ); + wait 5; +} + +hostmigrationwaitforplayers() +{ + level endon( "hostmigration_enoughplayers" ); + wait 15; +} + +hostmigrationtimerthink_internal() +{ + level endon( "host_migration_begin" ); + level endon( "host_migration_end" ); + self.hostmigrationcontrolsfrozen = 0; + while ( !isalive( self ) ) + { + self waittill( "spawned" ); + } + if ( isDefined( self._host_migration_link_entity ) ) + { + ent = spawn( "script_origin", self.origin ); + ent.angles = self.angles; + self linkto( ent ); + ent linkto( self._host_migration_link_entity, "tag_origin", self._host_migration_link_entity worldtolocalcoords( ent.origin ), ent.angles + self._host_migration_link_entity.angles ); + self._host_migration_link_helper = ent; +/# + println( "Linking player to ent " + self._host_migration_link_entity.targetname ); +#/ + } + self.hostmigrationcontrolsfrozen = 1; + self freezecontrols( 1 ); + level waittill( "host_migration_end" ); +} + +hostmigrationtimerthink() +{ + self endon( "disconnect" ); + level endon( "host_migration_begin" ); + hostmigrationtimerthink_internal(); + if ( self.hostmigrationcontrolsfrozen ) + { + self freezecontrols( 0 ); + self.hostmigrationcontrolsfrozen = 0; +/# + println( " Host migration unfreeze controls" ); +#/ + } + if ( isDefined( self._host_migration_link_entity ) ) + { + self unlink(); + self._host_migration_link_helper delete(); + self._host_migration_link_helper = undefined; + if ( isDefined( self._host_migration_link_entity._post_host_migration_thread ) ) + { + self thread [[ self._host_migration_link_entity._post_host_migration_thread ]]( self._host_migration_link_entity ); + } + self._host_migration_link_entity = undefined; + } +} + +waittillhostmigrationdone() +{ + if ( !isDefined( level.hostmigrationtimer ) ) + { + return 0; + } + starttime = getTime(); + level waittill( "host_migration_end" ); + return getTime() - starttime; +} + +waittillhostmigrationstarts( duration ) +{ + if ( isDefined( level.hostmigrationtimer ) ) + { + return; + } + level endon( "host_migration_begin" ); + wait duration; +} + +waitlongdurationwithhostmigrationpause( duration ) +{ + if ( duration == 0 ) + { + return; + } +/# + assert( duration > 0 ); +#/ + starttime = getTime(); + endtime = getTime() + ( duration * 1000 ); + while ( getTime() < endtime ) + { + waittillhostmigrationstarts( ( endtime - getTime() ) / 1000 ); + if ( isDefined( level.hostmigrationtimer ) ) + { + timepassed = waittillhostmigrationdone(); + endtime += timepassed; + } + } + if ( getTime() != endtime ) + { +/# + println( "SCRIPT WARNING: gettime() = " + getTime() + " NOT EQUAL TO endtime = " + endtime ); +#/ + } + waittillhostmigrationdone(); + return getTime() - starttime; +} + +waitlongdurationwithgameendtimeupdate( duration ) +{ + if ( duration == 0 ) + { + return; + } +/# + assert( duration > 0 ); +#/ + starttime = getTime(); + endtime = getTime() + ( duration * 1000 ); + while ( getTime() < endtime ) + { + waittillhostmigrationstarts( ( endtime - getTime() ) / 1000 ); + while ( isDefined( level.hostmigrationtimer ) ) + { + endtime += 1000; + setgameendtime( int( endtime ) ); + wait 1; + } + } +/# + if ( getTime() != endtime ) + { + println( "SCRIPT WARNING: gettime() = " + getTime() + " NOT EQUAL TO endtime = " + endtime ); +#/ + } + while ( isDefined( level.hostmigrationtimer ) ) + { + endtime += 1000; + setgameendtime( int( endtime ) ); + wait 1; + } + return getTime() - starttime; +} + +find_alternate_player_place( v_origin, min_radius, max_radius, max_height, ignore_targetted_nodes ) +{ + found_node = undefined; + a_nodes = getnodesinradiussorted( v_origin, max_radius, min_radius, max_height, "pathnodes" ); + while ( isDefined( a_nodes ) && a_nodes.size > 0 ) + { + a_player_volumes = getentarray( "player_volume", "script_noteworthy" ); + index = a_nodes.size - 1; + i = index; + while ( i >= 0 ) + { + n_node = a_nodes[ i ]; + if ( ignore_targetted_nodes == 1 ) + { + if ( isDefined( n_node.target ) ) + { + i--; + continue; + } + } + else + { + if ( !positionwouldtelefrag( n_node.origin ) ) + { + if ( maps/mp/zombies/_zm_utility::check_point_in_enabled_zone( n_node.origin, 1, a_player_volumes ) ) + { + v_start = ( n_node.origin[ 0 ], n_node.origin[ 1 ], n_node.origin[ 2 ] + 30 ); + v_end = ( n_node.origin[ 0 ], n_node.origin[ 1 ], n_node.origin[ 2 ] - 30 ); + trace = bullettrace( v_start, v_end, 0, undefined ); + if ( trace[ "fraction" ] < 1 ) + { + override_abort = 0; + if ( isDefined( level._chugabud_reject_node_override_func ) ) + { + override_abort = [[ level._chugabud_reject_node_override_func ]]( v_origin, n_node ); + } + if ( !override_abort ) + { + found_node = n_node; + break; + } + } + } + } + } + else + { + i--; + + } + } + } + return found_node; +} + +hostmigration_put_player_in_better_place() +{ + spawnpoint = undefined; + spawnpoint = find_alternate_player_place( self.origin, 50, 150, 64, 1 ); + if ( !isDefined( spawnpoint ) ) + { + spawnpoint = find_alternate_player_place( self.origin, 150, 400, 64, 1 ); + } + if ( !isDefined( spawnpoint ) ) + { + spawnpoint = find_alternate_player_place( self.origin, 50, 400, 256, 0 ); + } + 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 ) ) + { + _a559 = structs; + _k559 = getFirstArrayKey( _a559 ); + while ( isDefined( _k559 ) ) + { + struct = _a559[ _k559 ]; + while ( isDefined( struct.script_string ) ) + { + tokens = strtok( struct.script_string, " " ); + _a565 = tokens; + _k565 = getFirstArrayKey( _a565 ); + while ( isDefined( _k565 ) ) + { + token = _a565[ _k565 ]; + if ( token == match_string ) + { + spawnpoints[ spawnpoints.size ] = struct; + } + _k565 = getNextArrayKey( _a565, _k565 ); + } + } + _k559 = getNextArrayKey( _a559, _k559 ); + } + } + 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 ); + } + if ( isDefined( spawnpoint ) ) + { + self setorigin( spawnpoint.origin ); + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_hud.gsc b/patch_zm/maps/mp/gametypes_zm/_hud.gsc new file mode 100644 index 0000000..529ea3f --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_hud.gsc @@ -0,0 +1,167 @@ + +init() +{ + precacheshader( "progress_bar_bg" ); + precacheshader( "progress_bar_fg" ); + precacheshader( "progress_bar_fill" ); + precacheshader( "score_bar_bg" ); + level.uiparent = spawnstruct(); + level.uiparent.horzalign = "left"; + level.uiparent.vertalign = "top"; + level.uiparent.alignx = "left"; + level.uiparent.aligny = "top"; + level.uiparent.x = 0; + level.uiparent.y = 0; + level.uiparent.width = 0; + level.uiparent.height = 0; + level.uiparent.children = []; + level.fontheight = 12; + _a103 = level.teams; + _k103 = getFirstArrayKey( _a103 ); + while ( isDefined( _k103 ) ) + { + team = _a103[ _k103 ]; + level.hud[ team ] = spawnstruct(); + _k103 = getNextArrayKey( _a103, _k103 ); + } + level.primaryprogressbary = -61; + level.primaryprogressbarx = 0; + level.primaryprogressbarheight = 9; + level.primaryprogressbarwidth = 120; + level.primaryprogressbartexty = -75; + level.primaryprogressbartextx = 0; + level.primaryprogressbarfontsize = 1,4; + level.primaryprogressbarx_ss = 20; + level.primaryprogressbartextx_ss = 20; + level.primaryprogressbary_ss = 30; + level.primaryprogressbartexty_ss = 33; + level.primaryprogressbarheight_ss = 2; + level.secondaryprogressbary = -85; + level.secondaryprogressbarx = 0; + level.secondaryprogressbarheight = 9; + level.secondaryprogressbarwidth = 120; + level.secondaryprogressbartexty = -100; + level.secondaryprogressbartextx = 0; + level.secondaryprogressbarfontsize = 1,4; + level.secondaryprogressbarx_ss = 20; + level.secondaryprogressbartextx_ss = 20; + level.secondaryprogressbary_ss = 15; + level.secondaryprogressbartexty_ss = 0; + level.secondaryprogressbarheight_ss = 2; + level.teamprogressbary = 32; + level.teamprogressbarheight = 14; + level.teamprogressbarwidth = 192; + level.teamprogressbartexty = 8; + level.teamprogressbarfontsize = 1,65; + setdvar( "ui_generic_status_bar", 0 ); + level.lowertextyalign = "BOTTOM"; + level.lowertexty = -42; + level.lowertextfontsize = 1,4; + level.lowertextyalign_ss = "CENTER"; + level.lowertexty_ss = 40; + level.lowertextfontsize_ss = 1,4; +} + +fontpulseinit() +{ + self.basefontscale = self.fontscale; + self.maxfontscale = self.fontscale * 2; + self.inframes = 1,5; + self.outframes = 3; +} + +fontpulse( player ) +{ + self notify( "fontPulse" ); + self endon( "fontPulse" ); + self endon( "death" ); + player endon( "disconnect" ); + player endon( "joined_team" ); + player endon( "joined_spectators" ); + if ( self.outframes == 0 ) + { + self.fontscale = 0,01; + } + else + { + self.fontscale = self.fontscale; + } + if ( self.inframes > 0 ) + { + self changefontscaleovertime( self.inframes * 0,05 ); + self.fontscale = self.maxfontscale; + wait ( self.inframes * 0,05 ); + } + else + { + self.fontscale = self.maxfontscale; + self.alpha = 0; + self fadeovertime( self.outframes * 0,05 ); + self.alpha = 1; + } + if ( self.outframes > 0 ) + { + self changefontscaleovertime( self.outframes * 0,05 ); + self.fontscale = self.basefontscale; + } +} + +fadetoblackforxsec( startwait, blackscreenwait, fadeintime, fadeouttime, shadername, n_sort ) +{ + if ( !isDefined( n_sort ) ) + { + n_sort = 50; + } + wait startwait; + if ( !isDefined( self ) ) + { + return; + } + if ( !isDefined( self.blackscreen ) ) + { + self.blackscreen = newclienthudelem( self ); + } + self.blackscreen.x = 0; + self.blackscreen.y = 0; + self.blackscreen.horzalign = "fullscreen"; + self.blackscreen.vertalign = "fullscreen"; + self.blackscreen.foreground = 0; + self.blackscreen.hidewhendead = 0; + self.blackscreen.hidewheninmenu = 1; + self.blackscreen.sort = n_sort; + if ( isDefined( shadername ) ) + { + self.blackscreen setshader( shadername, 640, 480 ); + } + else + { + self.blackscreen setshader( "black", 640, 480 ); + } + self.blackscreen.alpha = 0; + if ( fadeintime > 0 ) + { + self.blackscreen fadeovertime( fadeintime ); + } + self.blackscreen.alpha = 1; + wait fadeintime; + if ( !isDefined( self.blackscreen ) ) + { + return; + } + wait blackscreenwait; + if ( !isDefined( self.blackscreen ) ) + { + return; + } + if ( fadeouttime > 0 ) + { + self.blackscreen fadeovertime( fadeouttime ); + } + self.blackscreen.alpha = 0; + wait fadeouttime; + if ( isDefined( self.blackscreen ) ) + { + self.blackscreen destroy(); + self.blackscreen = undefined; + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_hud_message.gsc b/patch_zm/maps/mp/gametypes_zm/_hud_message.gsc new file mode 100644 index 0000000..2425d13 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_hud_message.gsc @@ -0,0 +1,1359 @@ +#include maps/mp/_utility; +#include maps/mp/gametypes_zm/_globallogic_audio; +#include maps/mp/_music; +#include maps/mp/gametypes_zm/_hud_message; +#include maps/mp/gametypes_zm/_hud_util; + +init() +{ + precachestring( &"MENU_POINTS" ); + precachestring( &"MP_FIRSTPLACE_NAME" ); + precachestring( &"MP_SECONDPLACE_NAME" ); + precachestring( &"MP_THIRDPLACE_NAME" ); + precachestring( &"MP_WAGER_PLACE_NAME" ); + precachestring( &"MP_MATCH_BONUS_IS" ); + precachestring( &"MP_CODPOINTS_MATCH_BONUS_IS" ); + precachestring( &"MP_WAGER_WINNINGS_ARE" ); + precachestring( &"MP_WAGER_SIDEBET_WINNINGS_ARE" ); + precachestring( &"MP_WAGER_IN_THE_MONEY" ); + precachestring( &"faction_popup" ); + game[ "strings" ][ "draw" ] = &"MP_DRAW_CAPS"; + game[ "strings" ][ "round_draw" ] = &"MP_ROUND_DRAW_CAPS"; + game[ "strings" ][ "round_win" ] = &"MP_ROUND_WIN_CAPS"; + game[ "strings" ][ "round_loss" ] = &"MP_ROUND_LOSS_CAPS"; + game[ "strings" ][ "victory" ] = &"MP_VICTORY_CAPS"; + game[ "strings" ][ "defeat" ] = &"MP_DEFEAT_CAPS"; + game[ "strings" ][ "game_over" ] = &"MP_GAME_OVER_CAPS"; + game[ "strings" ][ "halftime" ] = &"MP_HALFTIME_CAPS"; + game[ "strings" ][ "overtime" ] = &"MP_OVERTIME_CAPS"; + game[ "strings" ][ "roundend" ] = &"MP_ROUNDEND_CAPS"; + game[ "strings" ][ "intermission" ] = &"MP_INTERMISSION_CAPS"; + game[ "strings" ][ "side_switch" ] = &"MP_SWITCHING_SIDES_CAPS"; + game[ "strings" ][ "match_bonus" ] = &"MP_MATCH_BONUS_IS"; + game[ "strings" ][ "codpoints_match_bonus" ] = &"MP_CODPOINTS_MATCH_BONUS_IS"; + game[ "strings" ][ "wager_winnings" ] = &"MP_WAGER_WINNINGS_ARE"; + game[ "strings" ][ "wager_sidebet_winnings" ] = &"MP_WAGER_SIDEBET_WINNINGS_ARE"; + game[ "strings" ][ "wager_inthemoney" ] = &"MP_WAGER_IN_THE_MONEY_CAPS"; + game[ "strings" ][ "wager_loss" ] = &"MP_WAGER_LOSS_CAPS"; + game[ "strings" ][ "wager_topwinners" ] = &"MP_WAGER_TOPWINNERS"; + game[ "menu_endgameupdate" ] = "endgameupdate"; + precachemenu( game[ "menu_endgameupdate" ] ); + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread hintmessagedeaththink(); + player thread lowermessagethink(); + player thread initnotifymessage(); + player thread initcustomgametypeheader(); + } +} + +initcustomgametypeheader() +{ + font = "default"; + titlesize = 2,5; + self.customgametypeheader = createfontstring( font, titlesize ); + self.customgametypeheader setpoint( "TOP", undefined, 0, 30 ); + self.customgametypeheader.glowalpha = 1; + self.customgametypeheader.hidewheninmenu = 1; + self.customgametypeheader.archived = 0; + self.customgametypeheader.color = ( 1, 1, 0,6 ); + self.customgametypeheader.alpha = 1; + titlesize = 2; + self.customgametypesubheader = createfontstring( font, titlesize ); + self.customgametypesubheader setparent( self.customgametypeheader ); + self.customgametypesubheader setpoint( "TOP", "BOTTOM", 0, 0 ); + self.customgametypesubheader.glowalpha = 1; + self.customgametypesubheader.hidewheninmenu = 1; + self.customgametypesubheader.archived = 0; + self.customgametypesubheader.color = ( 1, 1, 0,6 ); + self.customgametypesubheader.alpha = 1; +} + +hintmessage( hinttext, duration ) +{ + notifydata = spawnstruct(); + notifydata.notifytext = hinttext; + notifydata.duration = duration; + notifymessage( notifydata ); +} + +hintmessageplayers( players, hinttext, duration ) +{ + notifydata = spawnstruct(); + notifydata.notifytext = hinttext; + notifydata.duration = duration; + i = 0; + while ( i < players.size ) + { + players[ i ] notifymessage( notifydata ); + i++; + } +} + +showinitialfactionpopup( team ) +{ + self luinotifyevent( &"faction_popup", 1, game[ "strings" ][ team + "_name" ] ); + maps/mp/gametypes_zm/_hud_message::oldnotifymessage( undefined, undefined, undefined, undefined ); +} + +initnotifymessage() +{ + if ( !sessionmodeiszombiesgame() ) + { + if ( self issplitscreen() ) + { + titlesize = 2; + textsize = 1,4; + iconsize = 24; + font = "extrabig"; + point = "TOP"; + relativepoint = "BOTTOM"; + yoffset = 30; + xoffset = 30; + } + else + { + titlesize = 2,5; + textsize = 1,75; + iconsize = 30; + font = "extrabig"; + point = "TOP"; + relativepoint = "BOTTOM"; + yoffset = 0; + xoffset = 0; + } + } + else if ( self issplitscreen() ) + { + titlesize = 2; + textsize = 1,4; + iconsize = 24; + font = "extrabig"; + point = "TOP"; + relativepoint = "BOTTOM"; + yoffset = 30; + xoffset = 30; + } + else + { + titlesize = 2,5; + textsize = 1,75; + iconsize = 30; + font = "extrabig"; + point = "BOTTOM LEFT"; + relativepoint = "TOP"; + yoffset = 0; + xoffset = 0; + } + self.notifytitle = createfontstring( font, titlesize ); + self.notifytitle setpoint( point, undefined, xoffset, yoffset ); + self.notifytitle.glowalpha = 1; + self.notifytitle.hidewheninmenu = 1; + self.notifytitle.archived = 0; + self.notifytitle.alpha = 0; + self.notifytext = createfontstring( font, textsize ); + self.notifytext setparent( self.notifytitle ); + self.notifytext setpoint( point, relativepoint, 0, 0 ); + self.notifytext.glowalpha = 1; + self.notifytext.hidewheninmenu = 1; + self.notifytext.archived = 0; + self.notifytext.alpha = 0; + self.notifytext2 = createfontstring( font, textsize ); + self.notifytext2 setparent( self.notifytitle ); + self.notifytext2 setpoint( point, relativepoint, 0, 0 ); + self.notifytext2.glowalpha = 1; + self.notifytext2.hidewheninmenu = 1; + self.notifytext2.archived = 0; + self.notifytext2.alpha = 0; + self.notifyicon = createicon( "white", iconsize, iconsize ); + self.notifyicon setparent( self.notifytext2 ); + self.notifyicon setpoint( point, relativepoint, 0, 0 ); + self.notifyicon.hidewheninmenu = 1; + self.notifyicon.archived = 0; + self.notifyicon.alpha = 0; + self.doingnotify = 0; + self.notifyqueue = []; +} + +oldnotifymessage( titletext, notifytext, iconname, glowcolor, sound, duration ) +{ + if ( level.wagermatch && !level.teambased ) + { + return; + } + notifydata = spawnstruct(); + notifydata.titletext = titletext; + notifydata.notifytext = notifytext; + notifydata.iconname = iconname; + notifydata.sound = sound; + notifydata.duration = duration; + self.startmessagenotifyqueue[ self.startmessagenotifyqueue.size ] = notifydata; + self notify( "received award" ); +} + +notifymessage( notifydata ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self.messagenotifyqueue[ self.messagenotifyqueue.size ] = notifydata; + self notify( "received award" ); +} + +shownotifymessage( notifydata, duration ) +{ + self endon( "disconnect" ); + self.doingnotify = 1; + waitrequirevisibility( 0 ); + self notify( "notifyMessageBegin" ); + self thread resetoncancel(); + if ( isDefined( notifydata.sound ) ) + { + self playlocalsound( notifydata.sound ); + } + if ( isDefined( notifydata.musicstate ) ) + { + self maps/mp/_music::setmusicstate( notifydata.music ); + } + if ( isDefined( notifydata.leadersound ) ) + { + self maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( notifydata.leadersound ); + } + if ( isDefined( notifydata.glowcolor ) ) + { + glowcolor = notifydata.glowcolor; + } + else + { + glowcolor = ( 1, 1, 1 ); + } + if ( isDefined( notifydata.color ) ) + { + color = notifydata.color; + } + else + { + color = ( 1, 1, 1 ); + } + anchorelem = self.notifytitle; + if ( isDefined( notifydata.titletext ) ) + { + if ( isDefined( notifydata.titlelabel ) ) + { + self.notifytitle.label = notifydata.titlelabel; + } + else + { + self.notifytitle.label = &""; + } + if ( isDefined( notifydata.titlelabel ) && !isDefined( notifydata.titleisstring ) ) + { + self.notifytitle setvalue( notifydata.titletext ); + } + else + { + self.notifytitle settext( notifydata.titletext ); + } + self.notifytitle setcod7decodefx( 200, int( duration * 1000 ), 600 ); + self.notifytitle.glowcolor = glowcolor; + self.notifytitle.color = color; + self.notifytitle.alpha = 1; + } + if ( isDefined( notifydata.notifytext ) ) + { + if ( isDefined( notifydata.textlabel ) ) + { + self.notifytext.label = notifydata.textlabel; + } + else + { + self.notifytext.label = &""; + } + if ( isDefined( notifydata.textlabel ) && !isDefined( notifydata.textisstring ) ) + { + self.notifytext setvalue( notifydata.notifytext ); + } + else + { + self.notifytext settext( notifydata.notifytext ); + } + self.notifytext setcod7decodefx( 100, int( duration * 1000 ), 600 ); + self.notifytext.glowcolor = glowcolor; + self.notifytext.color = color; + self.notifytext.alpha = 1; + anchorelem = self.notifytext; + } + if ( isDefined( notifydata.notifytext2 ) ) + { + if ( self issplitscreen() ) + { + if ( isDefined( notifydata.text2label ) ) + { + self iprintlnbold( notifydata.text2label, notifydata.notifytext2 ); + } + else + { + self iprintlnbold( notifydata.notifytext2 ); + } + } + else + { + self.notifytext2 setparent( anchorelem ); + if ( isDefined( notifydata.text2label ) ) + { + self.notifytext2.label = notifydata.text2label; + } + else + { + self.notifytext2.label = &""; + } + self.notifytext2 settext( notifydata.notifytext2 ); + self.notifytext2 setpulsefx( 100, int( duration * 1000 ), 1000 ); + self.notifytext2.glowcolor = glowcolor; + self.notifytext2.color = color; + self.notifytext2.alpha = 1; + anchorelem = self.notifytext2; + } + } + if ( isDefined( notifydata.iconname ) ) + { + iconwidth = 60; + iconheight = 60; + if ( isDefined( notifydata.iconwidth ) ) + { + iconwidth = notifydata.iconwidth; + } + if ( isDefined( notifydata.iconheight ) ) + { + iconheight = notifydata.iconheight; + } + self.notifyicon setparent( anchorelem ); + self.notifyicon setshader( notifydata.iconname, iconwidth, iconheight ); + self.notifyicon.alpha = 0; + self.notifyicon fadeovertime( 1 ); + self.notifyicon.alpha = 1; + waitrequirevisibility( duration ); + self.notifyicon fadeovertime( 0,75 ); + self.notifyicon.alpha = 0; + } + else + { + waitrequirevisibility( duration ); + } + self notify( "notifyMessageDone" ); + self.doingnotify = 0; +} + +waitrequirevisibility( waittime ) +{ + interval = 0,05; + while ( !self canreadtext() ) + { + wait interval; + } + while ( waittime > 0 ) + { + wait interval; + if ( self canreadtext() ) + { + waittime -= interval; + } + } +} + +canreadtext() +{ + return 1; +} + +resetondeath() +{ + self endon( "notifyMessageDone" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self waittill( "death" ); + resetnotify(); +} + +resetoncancel() +{ + self notify( "resetOnCancel" ); + self endon( "resetOnCancel" ); + self endon( "notifyMessageDone" ); + self endon( "disconnect" ); + level waittill( "cancel_notify" ); + resetnotify(); +} + +resetnotify() +{ + self.notifytitle.alpha = 0; + self.notifytext.alpha = 0; + self.notifyicon.alpha = 0; + self.doingnotify = 0; +} + +hintmessagedeaththink() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "death" ); + if ( isDefined( self.hintmessage ) ) + { + self.hintmessage destroyelem(); + } + } +} + +lowermessagethink() +{ + self endon( "disconnect" ); + self.lowermessage = createfontstring( "default", level.lowertextfontsize ); + self.lowermessage setpoint( "CENTER", level.lowertextyalign, 0, level.lowertexty ); + self.lowermessage settext( "" ); + self.lowermessage.archived = 0; + timerfontsize = 1,5; + if ( self issplitscreen() ) + { + timerfontsize = 1,4; + } + self.lowertimer = createfontstring( "default", timerfontsize ); + self.lowertimer setparent( self.lowermessage ); + self.lowertimer setpoint( "TOP", "BOTTOM", 0, 0 ); + self.lowertimer settext( "" ); + self.lowertimer.archived = 0; +} + +setmatchscorehudelemforteam( team ) +{ + if ( level.roundscorecarry ) + { + self setvalue( getteamscore( team ) ); + } + else + { + self setvalue( getroundswon( team ) ); + } +} + +teamoutcomenotify( winner, isround, endreasontext ) +{ + self endon( "disconnect" ); + self notify( "reset_outcome" ); + team = self.pers[ "team" ]; + while ( isDefined( team ) && team == "spectator" ) + { + i = 0; + while ( i < level.players.size ) + { + if ( self.currentspectatingclient == level.players[ i ].clientid ) + { + team = level.players[ i ].pers[ "team" ]; + break; + } + else + { + i++; + } + } + } + if ( !isDefined( team ) || !isDefined( level.teams[ team ] ) ) + { + team = "allies"; + } + while ( self.doingnotify ) + { + wait 0,05; + } + self endon( "reset_outcome" ); + headerfont = "extrabig"; + font = "default"; + if ( self issplitscreen() ) + { + titlesize = 2; + textsize = 1,5; + iconsize = 30; + spacing = 10; + } + else + { + titlesize = 3; + textsize = 2; + iconsize = 70; + spacing = 25; + } + duration = 60000; + outcometitle = createfontstring( headerfont, titlesize ); + outcometitle setpoint( "TOP", undefined, 0, 30 ); + outcometitle.glowalpha = 1; + outcometitle.hidewheninmenu = 0; + outcometitle.archived = 0; + outcometext = createfontstring( font, 2 ); + outcometext setparent( outcometitle ); + outcometext setpoint( "TOP", "BOTTOM", 0, 0 ); + outcometext.glowalpha = 1; + outcometext.hidewheninmenu = 0; + outcometext.archived = 0; + if ( winner == "halftime" ) + { + outcometitle settext( game[ "strings" ][ "halftime" ] ); + outcometitle.color = ( 1, 1, 1 ); + winner = "allies"; + } + else if ( winner == "intermission" ) + { + outcometitle settext( game[ "strings" ][ "intermission" ] ); + outcometitle.color = ( 1, 1, 1 ); + winner = "allies"; + } + else if ( winner == "roundend" ) + { + outcometitle settext( game[ "strings" ][ "roundend" ] ); + outcometitle.color = ( 1, 1, 1 ); + winner = "allies"; + } + else if ( winner == "overtime" ) + { + outcometitle settext( game[ "strings" ][ "overtime" ] ); + outcometitle.color = ( 1, 1, 1 ); + winner = "allies"; + } + else if ( winner == "tie" ) + { + if ( isround ) + { + outcometitle settext( game[ "strings" ][ "round_draw" ] ); + } + else + { + outcometitle settext( game[ "strings" ][ "draw" ] ); + } + outcometitle.color = ( 0,29, 0,61, 0,7 ); + winner = "allies"; + } + else if ( isDefined( self.pers[ "team" ] ) && winner == team ) + { + if ( isround ) + { + outcometitle settext( game[ "strings" ][ "round_win" ] ); + } + else + { + outcometitle settext( game[ "strings" ][ "victory" ] ); + } + outcometitle.color = ( 0,42, 0,68, 0,46 ); + } + else + { + if ( isround ) + { + outcometitle settext( game[ "strings" ][ "round_loss" ] ); + } + else + { + outcometitle settext( game[ "strings" ][ "defeat" ] ); + } + outcometitle.color = ( 0,73, 0,29, 0,19 ); + } + outcometext settext( endreasontext ); + outcometitle setcod7decodefx( 200, duration, 600 ); + outcometext setpulsefx( 100, duration, 1000 ); + iconspacing = 100; + currentx = ( ( level.teamcount - 1 ) * -1 * iconspacing ) / 2; + teamicons = []; + teamicons[ team ] = createicon( game[ "icons" ][ team ], iconsize, iconsize ); + teamicons[ team ] setparent( outcometext ); + teamicons[ team ] setpoint( "TOP", "BOTTOM", currentx, spacing ); + teamicons[ team ].hidewheninmenu = 0; + teamicons[ team ].archived = 0; + teamicons[ team ].alpha = 0; + teamicons[ team ] fadeovertime( 0,5 ); + teamicons[ team ].alpha = 1; + currentx += iconspacing; + _a607 = level.teams; + _k607 = getFirstArrayKey( _a607 ); + while ( isDefined( _k607 ) ) + { + enemyteam = _a607[ _k607 ]; + if ( team == enemyteam ) + { + } + else + { + teamicons[ enemyteam ] = createicon( game[ "icons" ][ enemyteam ], iconsize, iconsize ); + teamicons[ enemyteam ] setparent( outcometext ); + teamicons[ enemyteam ] setpoint( "TOP", "BOTTOM", currentx, spacing ); + teamicons[ enemyteam ].hidewheninmenu = 0; + teamicons[ enemyteam ].archived = 0; + teamicons[ enemyteam ].alpha = 0; + teamicons[ enemyteam ] fadeovertime( 0,5 ); + teamicons[ enemyteam ].alpha = 1; + currentx += iconspacing; + } + _k607 = getNextArrayKey( _a607, _k607 ); + } + teamscores = []; + teamscores[ team ] = createfontstring( font, titlesize ); + teamscores[ team ] setparent( teamicons[ team ] ); + teamscores[ team ] setpoint( "TOP", "BOTTOM", 0, spacing ); + teamscores[ team ].glowalpha = 1; + if ( isround ) + { + teamscores[ team ] setvalue( getteamscore( team ) ); + } + else + { + teamscores[ team ] [[ level.setmatchscorehudelemforteam ]]( team ); + } + teamscores[ team ].hidewheninmenu = 0; + teamscores[ team ].archived = 0; + teamscores[ team ] setpulsefx( 100, duration, 1000 ); + _a641 = level.teams; + _k641 = getFirstArrayKey( _a641 ); + while ( isDefined( _k641 ) ) + { + enemyteam = _a641[ _k641 ]; + if ( team == enemyteam ) + { + } + else + { + teamscores[ enemyteam ] = createfontstring( headerfont, titlesize ); + teamscores[ enemyteam ] setparent( teamicons[ enemyteam ] ); + teamscores[ enemyteam ] setpoint( "TOP", "BOTTOM", 0, spacing ); + teamscores[ enemyteam ].glowalpha = 1; + if ( isround ) + { + teamscores[ enemyteam ] setvalue( getteamscore( enemyteam ) ); + } + else + { + teamscores[ enemyteam ] [[ level.setmatchscorehudelemforteam ]]( enemyteam ); + } + teamscores[ enemyteam ].hidewheninmenu = 0; + teamscores[ enemyteam ].archived = 0; + teamscores[ enemyteam ] setpulsefx( 100, duration, 1000 ); + } + _k641 = getNextArrayKey( _a641, _k641 ); + } + font = "objective"; + matchbonus = undefined; + if ( isDefined( self.matchbonus ) ) + { + matchbonus = createfontstring( font, 2 ); + matchbonus setparent( outcometext ); + matchbonus setpoint( "TOP", "BOTTOM", 0, iconsize + ( spacing * 3 ) + teamscores[ team ].height ); + matchbonus.glowalpha = 1; + matchbonus.hidewheninmenu = 0; + matchbonus.archived = 0; + matchbonus.label = game[ "strings" ][ "match_bonus" ]; + matchbonus setvalue( self.matchbonus ); + } + self thread resetoutcomenotify( teamicons, teamscores, outcometitle, outcometext ); +} + +teamoutcomenotifyzombie( winner, isround, endreasontext ) +{ + self endon( "disconnect" ); + self notify( "reset_outcome" ); + team = self.pers[ "team" ]; + while ( isDefined( team ) && team == "spectator" ) + { + i = 0; + while ( i < level.players.size ) + { + if ( self.currentspectatingclient == level.players[ i ].clientid ) + { + team = level.players[ i ].pers[ "team" ]; + break; + } + else + { + i++; + } + } + } + if ( !isDefined( team ) || !isDefined( level.teams[ team ] ) ) + { + team = "allies"; + } + while ( self.doingnotify ) + { + wait 0,05; + } + self endon( "reset_outcome" ); + if ( self issplitscreen() ) + { + titlesize = 2; + spacing = 10; + font = "default"; + } + else + { + titlesize = 3; + spacing = 50; + font = "objective"; + } + outcometitle = createfontstring( font, titlesize ); + outcometitle setpoint( "TOP", undefined, 0, spacing ); + outcometitle.glowalpha = 1; + outcometitle.hidewheninmenu = 0; + outcometitle.archived = 0; + outcometitle settext( endreasontext ); + outcometitle setpulsefx( 100, 60000, 1000 ); + self thread resetoutcomenotify( undefined, undefined, outcometitle ); +} + +outcomenotify( winner, isroundend, endreasontext ) +{ + self endon( "disconnect" ); + self notify( "reset_outcome" ); + while ( self.doingnotify ) + { + wait 0,05; + } + self endon( "reset_outcome" ); + headerfont = "extrabig"; + font = "default"; + if ( self issplitscreen() ) + { + titlesize = 2; + winnersize = 1,5; + othersize = 1,5; + iconsize = 30; + spacing = 10; + } + else + { + titlesize = 3; + winnersize = 2; + othersize = 1,5; + iconsize = 30; + spacing = 20; + } + duration = 60000; + players = level.placement[ "all" ]; + outcometitle = createfontstring( headerfont, titlesize ); + outcometitle setpoint( "TOP", undefined, 0, spacing ); + if ( !maps/mp/_utility::isoneround() && !isroundend ) + { + outcometitle settext( game[ "strings" ][ "game_over" ] ); + } + else + { + if ( isDefined( players[ 1 ] ) && players[ 0 ].score == players[ 1 ].score && players[ 0 ].deaths == players[ 1 ].deaths || self == players[ 0 ] && self == players[ 1 ] ) + { + outcometitle settext( game[ "strings" ][ "tie" ] ); + } + else + { + if ( isDefined( players[ 2 ] ) && players[ 0 ].score == players[ 2 ].score && players[ 0 ].deaths == players[ 2 ].deaths && self == players[ 2 ] ) + { + outcometitle settext( game[ "strings" ][ "tie" ] ); + } + else + { + if ( isDefined( players[ 0 ] ) && self == players[ 0 ] ) + { + outcometitle settext( game[ "strings" ][ "victory" ] ); + outcometitle.color = ( 0,42, 0,68, 0,46 ); + } + else + { + outcometitle settext( game[ "strings" ][ "defeat" ] ); + outcometitle.color = ( 0,73, 0,29, 0,19 ); + } + } + } + } + outcometitle.glowalpha = 1; + outcometitle.hidewheninmenu = 0; + outcometitle.archived = 0; + outcometitle setcod7decodefx( 200, duration, 600 ); + outcometext = createfontstring( font, 2 ); + outcometext setparent( outcometitle ); + outcometext setpoint( "TOP", "BOTTOM", 0, 0 ); + outcometext.glowalpha = 1; + outcometext.hidewheninmenu = 0; + outcometext.archived = 0; + outcometext settext( endreasontext ); + firsttitle = createfontstring( font, winnersize ); + firsttitle setparent( outcometext ); + firsttitle setpoint( "TOP", "BOTTOM", 0, spacing ); + firsttitle.glowalpha = 1; + firsttitle.hidewheninmenu = 0; + firsttitle.archived = 0; + if ( isDefined( players[ 0 ] ) ) + { + firsttitle.label = &"MP_FIRSTPLACE_NAME"; + firsttitle setplayernamestring( players[ 0 ] ); + firsttitle setcod7decodefx( 175, duration, 600 ); + } + secondtitle = createfontstring( font, othersize ); + secondtitle setparent( firsttitle ); + secondtitle setpoint( "TOP", "BOTTOM", 0, spacing ); + secondtitle.glowalpha = 1; + secondtitle.hidewheninmenu = 0; + secondtitle.archived = 0; + if ( isDefined( players[ 1 ] ) ) + { + secondtitle.label = &"MP_SECONDPLACE_NAME"; + secondtitle setplayernamestring( players[ 1 ] ); + secondtitle setcod7decodefx( 175, duration, 600 ); + } + thirdtitle = createfontstring( font, othersize ); + thirdtitle setparent( secondtitle ); + thirdtitle setpoint( "TOP", "BOTTOM", 0, spacing ); + thirdtitle setparent( secondtitle ); + thirdtitle.glowalpha = 1; + thirdtitle.hidewheninmenu = 0; + thirdtitle.archived = 0; + if ( isDefined( players[ 2 ] ) ) + { + thirdtitle.label = &"MP_THIRDPLACE_NAME"; + thirdtitle setplayernamestring( players[ 2 ] ); + thirdtitle setcod7decodefx( 175, duration, 600 ); + } + matchbonus = createfontstring( font, 2 ); + matchbonus setparent( thirdtitle ); + matchbonus setpoint( "TOP", "BOTTOM", 0, spacing ); + matchbonus.glowalpha = 1; + matchbonus.hidewheninmenu = 0; + matchbonus.archived = 0; + if ( isDefined( self.matchbonus ) ) + { + matchbonus.label = game[ "strings" ][ "match_bonus" ]; + matchbonus setvalue( self.matchbonus ); + } + self thread updateoutcome( firsttitle, secondtitle, thirdtitle ); + self thread resetoutcomenotify( undefined, undefined, outcometitle, outcometext, firsttitle, secondtitle, thirdtitle, matchbonus ); +} + +wageroutcomenotify( winner, endreasontext ) +{ + self endon( "disconnect" ); + self notify( "reset_outcome" ); + while ( self.doingnotify ) + { + wait 0,05; + } + setmatchflag( "enable_popups", 0 ); + self endon( "reset_outcome" ); + headerfont = "extrabig"; + font = "objective"; + if ( self issplitscreen() ) + { + titlesize = 2; + winnersize = 1,5; + othersize = 1,5; + iconsize = 30; + spacing = 2; + } + else + { + titlesize = 3; + winnersize = 2; + othersize = 1,5; + iconsize = 30; + spacing = 20; + } + halftime = 0; + if ( isDefined( level.sidebet ) && level.sidebet ) + { + halftime = 1; + } + duration = 60000; + players = level.placement[ "all" ]; + outcometitle = createfontstring( headerfont, titlesize ); + outcometitle setpoint( "TOP", undefined, 0, spacing ); + if ( halftime ) + { + outcometitle settext( game[ "strings" ][ "intermission" ] ); + outcometitle.color = ( 1, 1, 1 ); + outcometitle.glowcolor = ( 1, 1, 1 ); + } + else if ( isDefined( level.dontcalcwagerwinnings ) && level.dontcalcwagerwinnings == 1 ) + { + outcometitle settext( game[ "strings" ][ "wager_topwinners" ] ); + outcometitle.color = ( 0,42, 0,68, 0,46 ); + } + else + { + if ( isDefined( self.wagerwinnings ) && self.wagerwinnings > 0 ) + { + outcometitle settext( game[ "strings" ][ "wager_inthemoney" ] ); + outcometitle.color = ( 0,42, 0,68, 0,46 ); + } + else + { + outcometitle settext( game[ "strings" ][ "wager_loss" ] ); + outcometitle.color = ( 0,73, 0,29, 0,19 ); + } + } + outcometitle.glowalpha = 1; + outcometitle.hidewheninmenu = 0; + outcometitle.archived = 0; + outcometitle setcod7decodefx( 200, duration, 600 ); + outcometext = createfontstring( font, 2 ); + outcometext setparent( outcometitle ); + outcometext setpoint( "TOP", "BOTTOM", 0, 0 ); + outcometext.glowalpha = 1; + outcometext.hidewheninmenu = 0; + outcometext.archived = 0; + outcometext settext( endreasontext ); + playernamehudelems = []; + playercphudelems = []; + numplayers = players.size; + i = 0; + while ( i < numplayers ) + { + if ( !halftime && isDefined( players[ i ] ) ) + { + secondtitle = createfontstring( font, othersize ); + if ( playernamehudelems.size == 0 ) + { + secondtitle setparent( outcometext ); + secondtitle setpoint( "TOP_LEFT", "BOTTOM", -175, spacing * 3 ); + } + else + { + secondtitle setparent( playernamehudelems[ playernamehudelems.size - 1 ] ); + secondtitle setpoint( "TOP_LEFT", "BOTTOM_LEFT", 0, spacing ); + } + secondtitle.glowalpha = 1; + secondtitle.hidewheninmenu = 0; + secondtitle.archived = 0; + secondtitle.label = &"MP_WAGER_PLACE_NAME"; + secondtitle.playernum = i; + secondtitle setplayernamestring( players[ i ] ); + playernamehudelems[ playernamehudelems.size ] = secondtitle; + secondcp = createfontstring( font, othersize ); + secondcp setparent( secondtitle ); + secondcp setpoint( "TOP_RIGHT", "TOP_LEFT", 350, 0 ); + secondcp.glowalpha = 1; + secondcp.hidewheninmenu = 0; + secondcp.archived = 0; + secondcp.label = &"MENU_POINTS"; + secondcp.currentvalue = 0; + if ( isDefined( players[ i ].wagerwinnings ) ) + { + secondcp.targetvalue = players[ i ].wagerwinnings; + } + else + { + secondcp.targetvalue = 0; + } + if ( secondcp.targetvalue > 0 ) + { + secondcp.color = ( 0,42, 0,68, 0,46 ); + } + secondcp setvalue( 0 ); + playercphudelems[ playercphudelems.size ] = secondcp; + } + i++; + } + self thread updatewageroutcome( playernamehudelems, playercphudelems ); + self thread resetwageroutcomenotify( playernamehudelems, playercphudelems, outcometitle, outcometext ); + if ( halftime ) + { + return; + } + stillupdating = 1; + countupduration = 2; + cpincrement = 9999; + if ( isDefined( playercphudelems[ 0 ] ) ) + { + cpincrement = int( playercphudelems[ 0 ].targetvalue / ( countupduration / 0,05 ) ); + if ( cpincrement < 1 ) + { + cpincrement = 1; + } + } + while ( stillupdating ) + { + stillupdating = 0; + i = 0; + while ( i < playercphudelems.size ) + { + if ( isDefined( playercphudelems[ i ] ) && playercphudelems[ i ].currentvalue < playercphudelems[ i ].targetvalue ) + { + playercphudelems[ i ].currentvalue += cpincrement; + if ( playercphudelems[ i ].currentvalue > playercphudelems[ i ].targetvalue ) + { + playercphudelems[ i ].currentvalue = playercphudelems[ i ].targetvalue; + } + playercphudelems[ i ] setvalue( playercphudelems[ i ].currentvalue ); + stillupdating = 1; + } + i++; + } + wait 0,05; + } +} + +teamwageroutcomenotify( winner, isroundend, endreasontext ) +{ + self endon( "disconnect" ); + self notify( "reset_outcome" ); + team = self.pers[ "team" ]; + if ( !isDefined( team ) || !isDefined( level.teams[ team ] ) ) + { + team = "allies"; + } + wait 0,05; + while ( self.doingnotify ) + { + wait 0,05; + } + self endon( "reset_outcome" ); + headerfont = "extrabig"; + font = "objective"; + if ( self issplitscreen() ) + { + titlesize = 2; + textsize = 1,5; + iconsize = 30; + spacing = 10; + } + else + { + titlesize = 3; + textsize = 2; + iconsize = 70; + spacing = 15; + } + halftime = 0; + if ( isDefined( level.sidebet ) && level.sidebet ) + { + halftime = 1; + } + duration = 60000; + outcometitle = createfontstring( headerfont, titlesize ); + outcometitle setpoint( "TOP", undefined, 0, spacing ); + outcometitle.glowalpha = 1; + outcometitle.hidewheninmenu = 0; + outcometitle.archived = 0; + outcometext = createfontstring( font, 2 ); + outcometext setparent( outcometitle ); + outcometext setpoint( "TOP", "BOTTOM", 0, 0 ); + outcometext.glowalpha = 1; + outcometext.hidewheninmenu = 0; + outcometext.archived = 0; + if ( winner == "tie" ) + { + if ( isroundend ) + { + outcometitle settext( game[ "strings" ][ "round_draw" ] ); + } + else + { + outcometitle settext( game[ "strings" ][ "draw" ] ); + } + outcometitle.color = ( 1, 1, 1 ); + winner = "allies"; + } + else if ( winner == "overtime" ) + { + outcometitle settext( game[ "strings" ][ "overtime" ] ); + outcometitle.color = ( 1, 1, 1 ); + } + else if ( isDefined( self.pers[ "team" ] ) && winner == team ) + { + if ( isroundend ) + { + outcometitle settext( game[ "strings" ][ "round_win" ] ); + } + else + { + outcometitle settext( game[ "strings" ][ "victory" ] ); + } + outcometitle.color = ( 0,42, 0,68, 0,46 ); + } + else + { + if ( isroundend ) + { + outcometitle settext( game[ "strings" ][ "round_loss" ] ); + } + else + { + outcometitle settext( game[ "strings" ][ "defeat" ] ); + } + outcometitle.color = ( 0,73, 0,29, 0,19 ); + } + if ( !isDefined( level.dontshowendreason ) || !level.dontshowendreason ) + { + outcometext settext( endreasontext ); + } + outcometitle setpulsefx( 100, duration, 1000 ); + outcometext setpulsefx( 100, duration, 1000 ); + teamicons = []; + teamicons[ team ] = createicon( game[ "icons" ][ team ], iconsize, iconsize ); + teamicons[ team ] setparent( outcometext ); + teamicons[ team ] setpoint( "TOP", "BOTTOM", -60, spacing ); + teamicons[ team ].hidewheninmenu = 0; + teamicons[ team ].archived = 0; + teamicons[ team ].alpha = 0; + teamicons[ team ] fadeovertime( 0,5 ); + teamicons[ team ].alpha = 1; + _a1171 = level.teams; + _k1171 = getFirstArrayKey( _a1171 ); + while ( isDefined( _k1171 ) ) + { + enemyteam = _a1171[ _k1171 ]; + if ( team == enemyteam ) + { + } + else + { + teamicons[ enemyteam ] = createicon( game[ "icons" ][ enemyteam ], iconsize, iconsize ); + teamicons[ enemyteam ] setparent( outcometext ); + teamicons[ enemyteam ] setpoint( "TOP", "BOTTOM", 60, spacing ); + teamicons[ enemyteam ].hidewheninmenu = 0; + teamicons[ enemyteam ].archived = 0; + teamicons[ enemyteam ].alpha = 0; + teamicons[ enemyteam ] fadeovertime( 0,5 ); + teamicons[ enemyteam ].alpha = 1; + } + _k1171 = getNextArrayKey( _a1171, _k1171 ); + } + teamscores = []; + teamscores[ team ] = createfontstring( font, titlesize ); + teamscores[ team ] setparent( teamicons[ team ] ); + teamscores[ team ] setpoint( "TOP", "BOTTOM", 0, spacing ); + teamscores[ team ].glowalpha = 1; + teamscores[ team ] setvalue( getteamscore( team ) ); + teamscores[ team ].hidewheninmenu = 0; + teamscores[ team ].archived = 0; + teamscores[ team ] setpulsefx( 100, duration, 1000 ); + _a1197 = level.teams; + _k1197 = getFirstArrayKey( _a1197 ); + while ( isDefined( _k1197 ) ) + { + enemyteam = _a1197[ _k1197 ]; + if ( team == enemyteam ) + { + } + else + { + teamscores[ enemyteam ] = createfontstring( font, titlesize ); + teamscores[ enemyteam ] setparent( teamicons[ enemyteam ] ); + teamscores[ enemyteam ] setpoint( "TOP", "BOTTOM", 0, spacing ); + teamscores[ enemyteam ].glowalpha = 1; + teamscores[ enemyteam ] setvalue( getteamscore( enemyteam ) ); + teamscores[ enemyteam ].hidewheninmenu = 0; + teamscores[ enemyteam ].archived = 0; + teamscores[ enemyteam ] setpulsefx( 100, duration, 1000 ); + } + _k1197 = getNextArrayKey( _a1197, _k1197 ); + } + matchbonus = undefined; + sidebetwinnings = undefined; + if ( !isroundend && !halftime && isDefined( self.wagerwinnings ) ) + { + matchbonus = createfontstring( font, 2 ); + matchbonus setparent( outcometext ); + matchbonus setpoint( "TOP", "BOTTOM", 0, iconsize + ( spacing * 3 ) + teamscores[ team ].height ); + matchbonus.glowalpha = 1; + matchbonus.hidewheninmenu = 0; + matchbonus.archived = 0; + matchbonus.label = game[ "strings" ][ "wager_winnings" ]; + matchbonus setvalue( self.wagerwinnings ); + if ( isDefined( game[ "side_bets" ] ) && game[ "side_bets" ] ) + { + sidebetwinnings = createfontstring( font, 2 ); + sidebetwinnings setparent( matchbonus ); + sidebetwinnings setpoint( "TOP", "BOTTOM", 0, spacing ); + sidebetwinnings.glowalpha = 1; + sidebetwinnings.hidewheninmenu = 0; + sidebetwinnings.archived = 0; + sidebetwinnings.label = game[ "strings" ][ "wager_sidebet_winnings" ]; + sidebetwinnings setvalue( self.pers[ "wager_sideBetWinnings" ] ); + } + } + self thread resetoutcomenotify( teamicons, teamscores, outcometitle, outcometext, matchbonus, sidebetwinnings ); +} + +destroyhudelem( hudelem ) +{ + if ( isDefined( hudelem ) ) + { + hudelem destroyelem(); + } +} + +resetoutcomenotify( hudelemlist1, hudelemlist2, hudelem3, hudelem4, hudelem5, hudelem6, hudelem7, hudelem8, hudelem9, hudelem10 ) +{ + self endon( "disconnect" ); + self waittill( "reset_outcome" ); + destroyhudelem( hudelem3 ); + destroyhudelem( hudelem4 ); + destroyhudelem( hudelem5 ); + destroyhudelem( hudelem6 ); + destroyhudelem( hudelem7 ); + destroyhudelem( hudelem8 ); + destroyhudelem( hudelem9 ); + destroyhudelem( hudelem10 ); + while ( isDefined( hudelemlist1 ) ) + { + _a1263 = hudelemlist1; + _k1263 = getFirstArrayKey( _a1263 ); + while ( isDefined( _k1263 ) ) + { + elem = _a1263[ _k1263 ]; + destroyhudelem( elem ); + _k1263 = getNextArrayKey( _a1263, _k1263 ); + } + } + while ( isDefined( hudelemlist2 ) ) + { + _a1271 = hudelemlist2; + _k1271 = getFirstArrayKey( _a1271 ); + while ( isDefined( _k1271 ) ) + { + elem = _a1271[ _k1271 ]; + destroyhudelem( elem ); + _k1271 = getNextArrayKey( _a1271, _k1271 ); + } + } +} + +resetwageroutcomenotify( playernamehudelems, playercphudelems, outcometitle, outcometext ) +{ + self endon( "disconnect" ); + self waittill( "reset_outcome" ); + i = playernamehudelems.size - 1; + while ( i >= 0 ) + { + if ( isDefined( playernamehudelems[ i ] ) ) + { + playernamehudelems[ i ] destroy(); + } + i--; + + } + i = playercphudelems.size - 1; + while ( i >= 0 ) + { + if ( isDefined( playercphudelems[ i ] ) ) + { + playercphudelems[ i ] destroy(); + } + i--; + + } + if ( isDefined( outcometext ) ) + { + outcometext destroy(); + } + if ( isDefined( outcometitle ) ) + { + outcometitle destroy(); + } +} + +updateoutcome( firsttitle, secondtitle, thirdtitle ) +{ + self endon( "disconnect" ); + self endon( "reset_outcome" ); + while ( 1 ) + { + self waittill( "update_outcome" ); + players = level.placement[ "all" ]; + if ( isDefined( firsttitle ) && isDefined( players[ 0 ] ) ) + { + firsttitle setplayernamestring( players[ 0 ] ); + } + else + { + if ( isDefined( firsttitle ) ) + { + firsttitle.alpha = 0; + } + } + if ( isDefined( secondtitle ) && isDefined( players[ 1 ] ) ) + { + secondtitle setplayernamestring( players[ 1 ] ); + } + else + { + if ( isDefined( secondtitle ) ) + { + secondtitle.alpha = 0; + } + } + if ( isDefined( thirdtitle ) && isDefined( players[ 2 ] ) ) + { + thirdtitle setplayernamestring( players[ 2 ] ); + continue; + } + else + { + if ( isDefined( thirdtitle ) ) + { + thirdtitle.alpha = 0; + } + } + } +} + +updatewageroutcome( playernamehudelems, playercphudelems ) +{ + self endon( "disconnect" ); + self endon( "reset_outcome" ); + while ( 1 ) + { + self waittill( "update_outcome" ); + players = level.placement[ "all" ]; + i = 0; + while ( i < playernamehudelems.size ) + { + if ( isDefined( playernamehudelems[ i ] ) && isDefined( players[ playernamehudelems[ i ].playernum ] ) ) + { + playernamehudelems[ i ] setplayernamestring( players[ playernamehudelems[ i ].playernum ] ); + i++; + continue; + } + else + { + if ( isDefined( playernamehudelems[ i ] ) ) + { + playernamehudelems[ i ].alpha = 0; + } + if ( isDefined( playercphudelems[ i ] ) ) + { + playercphudelems[ i ].alpha = 0; + } + } + i++; + } + } +} + +setshoutcasterwaitingmessage() +{ + if ( !isDefined( self.waitingforplayerstext ) ) + { + self.waitingforplayerstext = createfontstring( "objective", 2,5 ); + self.waitingforplayerstext setpoint( "CENTER", "CENTER", 0, -80 ); + self.waitingforplayerstext.sort = 1001; + self.waitingforplayerstext settext( &"MP_WAITING_FOR_PLAYERS_SHOUTCASTER" ); + self.waitingforplayerstext.foreground = 0; + self.waitingforplayerstext.hidewheninmenu = 1; + } +} + +clearshoutcasterwaitingmessage() +{ + if ( isDefined( self.waitingforplayerstext ) ) + { + destroyhudelem( self.waitingforplayerstext ); + self.waitingforplayerstext = undefined; + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_hud_util.gsc b/patch_zm/maps/mp/gametypes_zm/_hud_util.gsc new file mode 100644 index 0000000..16b74f2 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_hud_util.gsc @@ -0,0 +1,1152 @@ +#include maps/mp/_utility; + +setparent( element ) +{ + if ( isDefined( self.parent ) && self.parent == element ) + { + return; + } + if ( isDefined( self.parent ) ) + { + self.parent removechild( self ); + } + self.parent = element; + self.parent addchild( self ); + if ( isDefined( self.point ) ) + { + self setpoint( self.point, self.relativepoint, self.xoffset, self.yoffset ); + } + else + { + self setpoint( "TOP" ); + } +} + +getparent() +{ + return self.parent; +} + +addchild( element ) +{ + element.index = self.children.size; + self.children[ self.children.size ] = element; +} + +removechild( element ) +{ + element.parent = undefined; + if ( self.children[ self.children.size - 1 ] != element ) + { + self.children[ element.index ] = self.children[ self.children.size - 1 ]; + self.children[ element.index ].index = element.index; + } + element.index = undefined; +} + +setpoint( point, relativepoint, xoffset, yoffset, movetime ) +{ + if ( !isDefined( movetime ) ) + { + movetime = 0; + } + element = self getparent(); + if ( movetime ) + { + self moveovertime( movetime ); + } + if ( !isDefined( xoffset ) ) + { + xoffset = 0; + } + self.xoffset = xoffset; + if ( !isDefined( yoffset ) ) + { + yoffset = 0; + } + self.yoffset = yoffset; + self.point = point; + self.alignx = "center"; + self.aligny = "middle"; + switch( point ) + { + case "CENTER": + break; + case "TOP": + self.aligny = "top"; + break; + case "BOTTOM": + self.aligny = "bottom"; + break; + case "LEFT": + self.alignx = "left"; + break; + case "RIGHT": + self.alignx = "right"; + break; + case "TOPRIGHT": + case "TOP_RIGHT": + self.aligny = "top"; + self.alignx = "right"; + break; + case "TOPLEFT": + case "TOP_LEFT": + self.aligny = "top"; + self.alignx = "left"; + break; + case "TOPCENTER": + self.aligny = "top"; + self.alignx = "center"; + break; + case "BOTTOM RIGHT": + case "BOTTOM_RIGHT": + self.aligny = "bottom"; + self.alignx = "right"; + break; + case "BOTTOM LEFT": + case "BOTTOM_LEFT": + self.aligny = "bottom"; + self.alignx = "left"; + break; + default: +/# + println( "^3Warning: unknown point passed to setPoint(): " + point ); +#/ + break; + } + if ( !isDefined( relativepoint ) ) + { + relativepoint = point; + } + self.relativepoint = relativepoint; + relativex = "center"; + relativey = "middle"; + switch( relativepoint ) + { + case "CENTER": + break; + case "TOP": + relativey = "top"; + break; + case "BOTTOM": + relativey = "bottom"; + break; + case "LEFT": + relativex = "left"; + break; + case "RIGHT": + relativex = "right"; + break; + case "TOPRIGHT": + case "TOP_RIGHT": + relativey = "top"; + relativex = "right"; + break; + case "TOPLEFT": + case "TOP_LEFT": + relativey = "top"; + relativex = "left"; + break; + case "TOPCENTER": + relativey = "top"; + relativex = "center"; + break; + case "BOTTOM RIGHT": + case "BOTTOM_RIGHT": + relativey = "bottom"; + relativex = "right"; + break; + case "BOTTOM LEFT": + case "BOTTOM_LEFT": + relativey = "bottom"; + relativex = "left"; + break; + default: +/# + println( "^3Warning: unknown relativePoint passed to setPoint(): " + relativepoint ); +#/ + break; + } + if ( element == level.uiparent ) + { + self.horzalign = relativex; + self.vertalign = relativey; + } + else + { + self.horzalign = element.horzalign; + self.vertalign = element.vertalign; + } + if ( relativex == element.alignx ) + { + offsetx = 0; + xfactor = 0; + } + else if ( relativex == "center" || element.alignx == "center" ) + { + offsetx = int( element.width / 2 ); + if ( relativex == "left" || element.alignx == "right" ) + { + xfactor = -1; + } + else + { + xfactor = 1; + } + } + else + { + offsetx = element.width; + if ( relativex == "left" ) + { + xfactor = -1; + } + else + { + xfactor = 1; + } + } + self.x = element.x + ( offsetx * xfactor ); + if ( relativey == element.aligny ) + { + offsety = 0; + yfactor = 0; + } + else if ( relativey == "middle" || element.aligny == "middle" ) + { + offsety = int( element.height / 2 ); + if ( relativey == "top" || element.aligny == "bottom" ) + { + yfactor = -1; + } + else + { + yfactor = 1; + } + } + else + { + offsety = element.height; + if ( relativey == "top" ) + { + yfactor = -1; + } + else + { + yfactor = 1; + } + } + self.y = element.y + ( offsety * yfactor ); + self.x += self.xoffset; + self.y += self.yoffset; + switch( self.elemtype ) + { + case "bar": + setpointbar( point, relativepoint, xoffset, yoffset ); + self.barframe setparent( self getparent() ); + self.barframe setpoint( point, relativepoint, xoffset, yoffset ); + break; + } + self updatechildren(); +} + +setpointbar( point, relativepoint, xoffset, yoffset ) +{ + self.bar.horzalign = self.horzalign; + self.bar.vertalign = self.vertalign; + self.bar.alignx = "left"; + self.bar.aligny = self.aligny; + self.bar.y = self.y; + if ( self.alignx == "left" ) + { + self.bar.x = self.x; + } + else if ( self.alignx == "right" ) + { + self.bar.x = self.x - self.width; + } + else + { + self.bar.x = self.x - int( self.width / 2 ); + } + if ( self.aligny == "top" ) + { + self.bar.y = self.y; + } + else + { + if ( self.aligny == "bottom" ) + { + self.bar.y = self.y; + } + } + self updatebar( self.bar.frac ); +} + +updatebar( barfrac, rateofchange ) +{ + if ( self.elemtype == "bar" ) + { + updatebarscale( barfrac, rateofchange ); + } +} + +updatebarscale( barfrac, rateofchange ) +{ + barwidth = int( ( self.width * barfrac ) + 0,5 ); + if ( !barwidth ) + { + barwidth = 1; + } + self.bar.frac = barfrac; + self.bar setshader( self.bar.shader, barwidth, self.height ); +/# + assert( barwidth <= self.width, "barWidth <= self.width: " + barwidth + " <= " + self.width + " - barFrac was " + barfrac ); +#/ + if ( isDefined( rateofchange ) && barwidth < self.width ) + { + if ( rateofchange > 0 ) + { +/# + assert( ( ( 1 - barfrac ) / rateofchange ) > 0, "barFrac: " + barfrac + "rateOfChange: " + rateofchange ); +#/ + self.bar scaleovertime( ( 1 - barfrac ) / rateofchange, self.width, self.height ); + } + else + { + if ( rateofchange < 0 ) + { +/# + assert( ( barfrac / ( -1 * rateofchange ) ) > 0, "barFrac: " + barfrac + "rateOfChange: " + rateofchange ); +#/ + self.bar scaleovertime( barfrac / ( -1 * rateofchange ), 1, self.height ); + } + } + } + self.bar.rateofchange = rateofchange; + self.bar.lastupdatetime = getTime(); +} + +createfontstring( font, fontscale ) +{ + fontelem = newclienthudelem( self ); + fontelem.elemtype = "font"; + fontelem.font = font; + fontelem.fontscale = fontscale; + fontelem.x = 0; + fontelem.y = 0; + fontelem.width = 0; + fontelem.height = int( level.fontheight * fontscale ); + fontelem.xoffset = 0; + fontelem.yoffset = 0; + fontelem.children = []; + fontelem setparent( level.uiparent ); + fontelem.hidden = 0; + return fontelem; +} + +createserverfontstring( font, fontscale, team ) +{ + if ( isDefined( team ) ) + { + fontelem = newteamhudelem( team ); + } + else + { + fontelem = newhudelem(); + } + fontelem.elemtype = "font"; + fontelem.font = font; + fontelem.fontscale = fontscale; + fontelem.x = 0; + fontelem.y = 0; + fontelem.width = 0; + fontelem.height = int( level.fontheight * fontscale ); + fontelem.xoffset = 0; + fontelem.yoffset = 0; + fontelem.children = []; + fontelem setparent( level.uiparent ); + fontelem.hidden = 0; + return fontelem; +} + +createservertimer( font, fontscale, team ) +{ + if ( isDefined( team ) ) + { + timerelem = newteamhudelem( team ); + } + else + { + timerelem = newhudelem(); + } + timerelem.elemtype = "timer"; + timerelem.font = font; + timerelem.fontscale = fontscale; + timerelem.x = 0; + timerelem.y = 0; + timerelem.width = 0; + timerelem.height = int( level.fontheight * fontscale ); + timerelem.xoffset = 0; + timerelem.yoffset = 0; + timerelem.children = []; + timerelem setparent( level.uiparent ); + timerelem.hidden = 0; + return timerelem; +} + +createclienttimer( font, fontscale ) +{ + timerelem = newclienthudelem( self ); + timerelem.elemtype = "timer"; + timerelem.font = font; + timerelem.fontscale = fontscale; + timerelem.x = 0; + timerelem.y = 0; + timerelem.width = 0; + timerelem.height = int( level.fontheight * fontscale ); + timerelem.xoffset = 0; + timerelem.yoffset = 0; + timerelem.children = []; + timerelem setparent( level.uiparent ); + timerelem.hidden = 0; + return timerelem; +} + +createicon( shader, width, height ) +{ + iconelem = newclienthudelem( self ); + iconelem.elemtype = "icon"; + iconelem.x = 0; + iconelem.y = 0; + iconelem.width = width; + iconelem.height = height; + iconelem.xoffset = 0; + iconelem.yoffset = 0; + iconelem.children = []; + iconelem setparent( level.uiparent ); + iconelem.hidden = 0; + if ( isDefined( shader ) ) + { + iconelem setshader( shader, width, height ); + } + return iconelem; +} + +createservericon( shader, width, height, team ) +{ + if ( isDefined( team ) ) + { + iconelem = newteamhudelem( team ); + } + else + { + iconelem = newhudelem(); + } + iconelem.elemtype = "icon"; + iconelem.x = 0; + iconelem.y = 0; + iconelem.width = width; + iconelem.height = height; + iconelem.xoffset = 0; + iconelem.yoffset = 0; + iconelem.children = []; + iconelem setparent( level.uiparent ); + iconelem.hidden = 0; + if ( isDefined( shader ) ) + { + iconelem setshader( shader, width, height ); + } + return iconelem; +} + +createserverbar( color, width, height, flashfrac, team, selected ) +{ + if ( isDefined( team ) ) + { + barelem = newteamhudelem( team ); + } + else + { + barelem = newhudelem(); + } + barelem.x = 0; + barelem.y = 0; + barelem.frac = 0; + barelem.color = color; + barelem.sort = -2; + barelem.shader = "progress_bar_fill"; + barelem setshader( "progress_bar_fill", width, height ); + barelem.hidden = 0; + if ( isDefined( flashfrac ) ) + { + barelem.flashfrac = flashfrac; + } + if ( isDefined( team ) ) + { + barelemframe = newteamhudelem( team ); + } + else + { + barelemframe = newhudelem(); + } + barelemframe.elemtype = "icon"; + barelemframe.x = 0; + barelemframe.y = 0; + barelemframe.width = width; + barelemframe.height = height; + barelemframe.xoffset = 0; + barelemframe.yoffset = 0; + barelemframe.bar = barelem; + barelemframe.barframe = barelemframe; + barelemframe.children = []; + barelemframe.sort = -1; + barelemframe.color = ( 1, 0, 0 ); + barelemframe setparent( level.uiparent ); + if ( isDefined( selected ) ) + { + barelemframe setshader( "progress_bar_fg_sel", width, height ); + } + else + { + barelemframe setshader( "progress_bar_fg", width, height ); + } + barelemframe.hidden = 0; + if ( isDefined( team ) ) + { + barelembg = newteamhudelem( team ); + } + else + { + barelembg = newhudelem(); + } + barelembg.elemtype = "bar"; + barelembg.x = 0; + barelembg.y = 0; + barelembg.width = width; + barelembg.height = height; + barelembg.xoffset = 0; + barelembg.yoffset = 0; + barelembg.bar = barelem; + barelembg.barframe = barelemframe; + barelembg.children = []; + barelembg.sort = -3; + barelembg.color = ( 1, 0, 0 ); + barelembg.alpha = 0,5; + barelembg setparent( level.uiparent ); + barelembg setshader( "progress_bar_bg", width, height ); + barelembg.hidden = 0; + return barelembg; +} + +createbar( color, width, height, flashfrac ) +{ + barelem = newclienthudelem( self ); + barelem.x = 0; + barelem.y = 0; + barelem.frac = 0; + barelem.color = color; + barelem.sort = -2; + barelem.shader = "progress_bar_fill"; + barelem setshader( "progress_bar_fill", width, height ); + barelem.hidden = 0; + if ( isDefined( flashfrac ) ) + { + barelem.flashfrac = flashfrac; + } + barelemframe = newclienthudelem( self ); + barelemframe.elemtype = "icon"; + barelemframe.x = 0; + barelemframe.y = 0; + barelemframe.width = width; + barelemframe.height = height; + barelemframe.xoffset = 0; + barelemframe.yoffset = 0; + barelemframe.bar = barelem; + barelemframe.barframe = barelemframe; + barelemframe.children = []; + barelemframe.sort = -1; + barelemframe.color = ( 1, 0, 0 ); + barelemframe setparent( level.uiparent ); + barelemframe.hidden = 0; + barelembg = newclienthudelem( self ); + barelembg.elemtype = "bar"; + if ( !self issplitscreen() ) + { + barelembg.x = -2; + barelembg.y = -2; + } + barelembg.width = width; + barelembg.height = height; + barelembg.xoffset = 0; + barelembg.yoffset = 0; + barelembg.bar = barelem; + barelembg.barframe = barelemframe; + barelembg.children = []; + barelembg.sort = -3; + barelembg.color = ( 1, 0, 0 ); + barelembg.alpha = 0,5; + barelembg setparent( level.uiparent ); + if ( !self issplitscreen() ) + { + barelembg setshader( "progress_bar_bg", width + 4, height + 4 ); + } + else + { + barelembg setshader( "progress_bar_bg", width + 0, height + 0 ); + } + barelembg.hidden = 0; + return barelembg; +} + +getcurrentfraction() +{ + frac = self.bar.frac; + if ( isDefined( self.bar.rateofchange ) ) + { + frac += ( getTime() - self.bar.lastupdatetime ) * self.bar.rateofchange; + if ( frac > 1 ) + { + frac = 1; + } + if ( frac < 0 ) + { + frac = 0; + } + } + return frac; +} + +createprimaryprogressbar() +{ + bar = undefined; + if ( self issplitscreen() ) + { + bar = self createbar( ( 1, 0, 0 ), level.primaryprogressbarwidth, level.primaryprogressbarheight_ss ); + bar setpoint( "TOP", undefined, level.primaryprogressbarx_ss, level.primaryprogressbary_ss ); + } + else + { + bar = self createbar( ( 1, 0, 0 ), level.primaryprogressbarwidth, level.primaryprogressbarheight ); + bar setpoint( "CENTER", undefined, level.primaryprogressbarx, level.primaryprogressbary ); + } + return bar; +} + +createprimaryprogressbartext() +{ + text = createfontstring( "objective", level.primaryprogressbarfontsize ); + if ( self issplitscreen() ) + { + text setpoint( "TOP", undefined, level.primaryprogressbartextx_ss, level.primaryprogressbartexty_ss ); + } + else + { + text setpoint( "CENTER", undefined, level.primaryprogressbartextx, level.primaryprogressbartexty ); + } + text.sort = -1; + return text; +} + +createsecondaryprogressbar() +{ + secondaryprogressbarheight = getdvarintdefault( "scr_secondaryProgressBarHeight", level.secondaryprogressbarheight ); + secondaryprogressbarx = getdvarintdefault( "scr_secondaryProgressBarX", level.secondaryprogressbarx ); + secondaryprogressbary = getdvarintdefault( "scr_secondaryProgressBarY", level.secondaryprogressbary ); + secondaryprogressbarheight_ss = getdvarintdefault( "scr_secondaryProgressBarHeight", level.secondaryprogressbarheight_ss ); + secondaryprogressbarx_ss = getdvarintdefault( "scr_secondaryProgressBarX", level.secondaryprogressbarx_ss ); + secondaryprogressbary_ss = getdvarintdefault( "scr_secondaryProgressBarY", level.secondaryprogressbary_ss ); + bar = undefined; + if ( self issplitscreen() ) + { + bar = self createbar( ( 1, 0, 0 ), level.secondaryprogressbarwidth, secondaryprogressbarheight_ss ); + bar setpoint( "TOP", undefined, secondaryprogressbarx_ss, secondaryprogressbary_ss ); + } + else + { + bar = self createbar( ( 1, 0, 0 ), level.secondaryprogressbarwidth, secondaryprogressbarheight ); + bar setpoint( "CENTER", undefined, secondaryprogressbarx, secondaryprogressbary ); + } + return bar; +} + +createsecondaryprogressbartext() +{ + secondaryprogressbartextx = getdvarintdefault( "scr_btx", level.secondaryprogressbartextx ); + secondaryprogressbartexty = getdvarintdefault( "scr_bty", level.secondaryprogressbartexty ); + secondaryprogressbartextx_ss = getdvarintdefault( "scr_btx", level.secondaryprogressbartextx_ss ); + secondaryprogressbartexty_ss = getdvarintdefault( "scr_bty", level.secondaryprogressbartexty_ss ); + text = createfontstring( "objective", level.primaryprogressbarfontsize ); + if ( self issplitscreen() ) + { + text setpoint( "TOP", undefined, secondaryprogressbartextx_ss, secondaryprogressbartexty_ss ); + } + else + { + text setpoint( "CENTER", undefined, secondaryprogressbartextx, secondaryprogressbartexty ); + } + text.sort = -1; + return text; +} + +createteamprogressbar( team ) +{ + bar = createserverbar( ( 1, 0, 0 ), level.teamprogressbarwidth, level.teamprogressbarheight, undefined, team ); + bar setpoint( "TOP", undefined, 0, level.teamprogressbary ); + return bar; +} + +createteamprogressbartext( team ) +{ + text = createserverfontstring( "default", level.teamprogressbarfontsize, team ); + text setpoint( "TOP", undefined, 0, level.teamprogressbartexty ); + return text; +} + +setflashfrac( flashfrac ) +{ + self.bar.flashfrac = flashfrac; +} + +hideelem() +{ + if ( self.hidden ) + { + return; + } + self.hidden = 1; + if ( self.alpha != 0 ) + { + self.alpha = 0; + } + if ( self.elemtype == "bar" || self.elemtype == "bar_shader" ) + { + self.bar.hidden = 1; + if ( self.bar.alpha != 0 ) + { + self.bar.alpha = 0; + } + self.barframe.hidden = 1; + if ( self.barframe.alpha != 0 ) + { + self.barframe.alpha = 0; + } + } +} + +showelem() +{ + if ( !self.hidden ) + { + return; + } + self.hidden = 0; + if ( self.elemtype == "bar" || self.elemtype == "bar_shader" ) + { + if ( self.alpha != 0,5 ) + { + self.alpha = 0,5; + } + self.bar.hidden = 0; + if ( self.bar.alpha != 1 ) + { + self.bar.alpha = 1; + } + self.barframe.hidden = 0; + if ( self.barframe.alpha != 1 ) + { + self.barframe.alpha = 1; + } + } + else + { + if ( self.alpha != 1 ) + { + self.alpha = 1; + } + } +} + +flashthread() +{ + self endon( "death" ); + if ( !self.hidden ) + { + self.alpha = 1; + } + while ( 1 ) + { + if ( self.frac >= self.flashfrac ) + { + if ( !self.hidden ) + { + self fadeovertime( 0,3 ); + self.alpha = 0,2; + wait 0,35; + self fadeovertime( 0,3 ); + self.alpha = 1; + } + wait 0,7; + continue; + } + else + { + if ( !self.hidden && self.alpha != 1 ) + { + self.alpha = 1; + } + wait 0,05; + } + } +} + +destroyelem() +{ + tempchildren = []; + index = 0; + while ( index < self.children.size ) + { + if ( isDefined( self.children[ index ] ) ) + { + tempchildren[ tempchildren.size ] = self.children[ index ]; + } + index++; + } + index = 0; + while ( index < tempchildren.size ) + { + tempchildren[ index ] setparent( self getparent() ); + index++; + } + if ( self.elemtype == "bar" || self.elemtype == "bar_shader" ) + { + self.bar destroy(); + self.barframe destroy(); + } + self destroy(); +} + +seticonshader( shader ) +{ + self setshader( shader, self.width, self.height ); +} + +setwidth( width ) +{ + self.width = width; +} + +setheight( height ) +{ + self.height = height; +} + +setsize( width, height ) +{ + self.width = width; + self.height = height; +} + +updatechildren() +{ + index = 0; + while ( index < self.children.size ) + { + child = self.children[ index ]; + child setpoint( child.point, child.relativepoint, child.xoffset, child.yoffset ); + index++; + } +} + +createloadouticon( verindex, horindex, xpos, ypos ) +{ + iconsize = 32; + if ( level.splitscreen ) + { + ypos -= 80 + ( iconsize * ( 3 - verindex ) ); + } + else + { + ypos -= 90 + ( iconsize * ( 3 - verindex ) ); + } + if ( level.splitscreen ) + { + xpos -= 5 + ( iconsize * horindex ); + } + else + { + xpos -= 10 + ( iconsize * horindex ); + } + icon = createicon( "white", iconsize, iconsize ); + icon setpoint( "BOTTOM RIGHT", "BOTTOM RIGHT", xpos, ypos ); + icon.horzalign = "user_right"; + icon.vertalign = "user_bottom"; + icon.archived = 0; + icon.foreground = 0; + return icon; +} + +setloadouticoncoords( verindex, horindex, xpos, ypos ) +{ + iconsize = 32; + if ( level.splitscreen ) + { + ypos -= 80 + ( iconsize * ( 3 - verindex ) ); + } + else + { + ypos -= 90 + ( iconsize * ( 3 - verindex ) ); + } + if ( level.splitscreen ) + { + xpos -= 5 + ( iconsize * horindex ); + } + else + { + xpos -= 10 + ( iconsize * horindex ); + } + self setpoint( "BOTTOM RIGHT", "BOTTOM RIGHT", xpos, ypos ); + self.horzalign = "user_right"; + self.vertalign = "user_bottom"; + self.archived = 0; + self.foreground = 0; + self.alpha = 1; +} + +setloadouttextcoords( xcoord ) +{ + self setpoint( "RIGHT", "LEFT", xcoord, 0 ); +} + +createloadouttext( icon, xcoord ) +{ + text = createfontstring( "small", 1 ); + text setparent( icon ); + text setpoint( "RIGHT", "LEFT", xcoord, 0 ); + text.archived = 0; + text.alignx = "right"; + text.aligny = "middle"; + text.foreground = 0; + return text; +} + +showloadoutattribute( iconelem, icon, alpha, textelem, text ) +{ + iconsize = 32; + iconelem.alpha = alpha; + if ( alpha ) + { + iconelem setshader( icon, iconsize, iconsize ); + } + if ( isDefined( textelem ) ) + { + textelem.alpha = alpha; + if ( alpha ) + { + textelem settext( text ); + } + } +} + +hideloadoutattribute( iconelem, fadetime, textelem, hidetextonly ) +{ + if ( isDefined( fadetime ) ) + { + if ( !isDefined( hidetextonly ) || !hidetextonly ) + { + iconelem fadeovertime( fadetime ); + } + if ( isDefined( textelem ) ) + { + textelem fadeovertime( fadetime ); + } + } + if ( !isDefined( hidetextonly ) || !hidetextonly ) + { + iconelem.alpha = 0; + } + if ( isDefined( textelem ) ) + { + textelem.alpha = 0; + } +} + +showperks() +{ + ypos = 40; + if ( !isDefined( self.perkhudelem ) ) + { + self.perkhudelem = createloadouticon( 0, 0, 200, ypos ); + } + else + { + self.perkhudelem setloadouticoncoords( 0, 0, 200, ypos ); + } + self.perkhudelem setperks( self ); + self.perkhudelem.x = -10; + self.perkhudelem.alpha = 0; + self.perkhudelem fadeovertime( 0,4 ); + self.perkhudelem.alpha = 1; + self.perkhudelem.hidewheninmenu = 1; +} + +showperk( index, perk, ypos ) +{ +/# + assert( game[ "state" ] != "postgame" ); +#/ + if ( !isDefined( self.perkicon ) ) + { + self.perkicon = []; + self.perkname = []; + } + if ( !isDefined( self.perkicon[ index ] ) ) + { +/# + assert( !isDefined( self.perkname[ index ] ) ); +#/ + self.perkicon[ index ] = createloadouticon( index, 0, 200, ypos ); + self.perkname[ index ] = createloadouttext( self.perkicon[ index ], 160 ); + } + else + { + self.perkicon[ index ] setloadouticoncoords( index, 0, 200, ypos ); + self.perkname[ index ] setloadouttextcoords( 160 ); + } + if ( perk != "perk_null" || perk == "weapon_null" && perk == "specialty_null" ) + { + alpha = 0; + } + else + { +/# + assert( isDefined( level.perknames[ perk ] ), perk ); +#/ + alpha = 1; + } + showloadoutattribute( self.perkicon[ index ], perk, alpha, self.perkname[ index ], level.perknames[ perk ] ); + self.perkicon[ index ] moveovertime( 0,3 ); + self.perkicon[ index ].x = -5; + self.perkicon[ index ].hidewheninmenu = 1; + self.perkname[ index ] moveovertime( 0,3 ); + self.perkname[ index ].x = -40; + self.perkname[ index ].hidewheninmenu = 1; +} + +hideperks( fadetime ) +{ + if ( level.perksenabled == 1 ) + { + if ( game[ "state" ] == "postgame" ) + { +/# + assert( !isDefined( self.perkhudelem ) ); +#/ + return; + } + } +/# + assert( isDefined( self.perkhudelem ) ); +#/ + if ( isDefined( self.perkhudelem ) ) + { + hideloadoutattribute( self.perkhudelem, fadetime ); + } +} + +hideperk( index, fadetime, hidetextonly ) +{ + if ( !isDefined( fadetime ) ) + { + fadetime = 0,05; + } + if ( level.perksenabled == 1 ) + { + if ( game[ "state" ] == "postgame" ) + { + if ( isDefined( self.perkicon ) ) + { +/# + assert( !isDefined( self.perkicon[ index ] ) ); +#/ +/# + assert( !isDefined( self.perkname[ index ] ) ); +#/ + } + return; + } +/# + assert( isDefined( self.perkicon[ index ] ) ); +#/ +/# + assert( isDefined( self.perkname[ index ] ) ); +#/ + if ( isDefined( self.perkicon ) && isDefined( self.perkicon[ index ] ) && isDefined( self.perkname ) && isDefined( self.perkname[ index ] ) ) + { + hideloadoutattribute( self.perkicon[ index ], fadetime, self.perkname[ index ], hidetextonly ); + } + } +} + +hideallperks( fadetime, hidetextonly ) +{ + if ( level.perksenabled == 1 ) + { + hideperks( fadetime ); + } +} + +showkillstreak( index, killstreak, xpos, ypos ) +{ +/# + assert( game[ "state" ] != "postgame" ); +#/ + if ( !isDefined( self.killstreakicon ) ) + { + self.killstreakicon = []; + } + if ( !isDefined( self.killstreakicon[ index ] ) ) + { + self.killstreakicon[ index ] = createloadouticon( 3, ( self.killstreak.size - 1 ) - index, xpos, ypos ); + } + if ( killstreak == "killstreak_null" || killstreak == "weapon_null" ) + { + alpha = 0; + } + else + { +/# + assert( isDefined( level.killstreakicons[ killstreak ] ), killstreak ); +#/ + alpha = 1; + } + showloadoutattribute( self.killstreakicon[ index ], level.killstreakicons[ killstreak ], alpha ); +} + +hidekillstreak( index, fadetime ) +{ + if ( iskillstreaksenabled() ) + { + if ( game[ "state" ] == "postgame" ) + { +/# + assert( !isDefined( self.killstreakicon[ index ] ) ); +#/ + return; + } +/# + assert( isDefined( self.killstreakicon[ index ] ) ); +#/ + hideloadoutattribute( self.killstreakicon[ index ], fadetime ); + } +} + +setgamemodeinfopoint() +{ + self.x = 5; + self.y = 120; + self.horzalign = "user_left"; + self.vertalign = "user_top"; + self.alignx = "left"; + self.aligny = "top"; +} diff --git a/patch_zm/maps/mp/gametypes_zm/_menus.gsc b/patch_zm/maps/mp/gametypes_zm/_menus.gsc new file mode 100644 index 0000000..97f9513 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_menus.gsc @@ -0,0 +1,175 @@ +#include maps/mp/gametypes_zm/_rank; +#include maps/mp/gametypes_zm/_globallogic; +#include maps/mp/_utility; + +init() +{ + precachestring( &"open_ingame_menu" ); + game[ "menu_team" ] = "team_marinesopfor"; + game[ "menu_initteam_allies" ] = "initteam_marines"; + game[ "menu_initteam_axis" ] = "initteam_opfor"; + game[ "menu_class" ] = "class"; + game[ "menu_changeclass" ] = "changeclass"; + game[ "menu_changeclass_offline" ] = "changeclass"; + game[ "menu_wager_side_bet" ] = "sidebet"; + game[ "menu_wager_side_bet_player" ] = "sidebet_player"; + game[ "menu_changeclass_wager" ] = "changeclass_wager"; + game[ "menu_changeclass_custom" ] = "changeclass_custom"; + game[ "menu_changeclass_barebones" ] = "changeclass_barebones"; + _a18 = level.teams; + _k18 = getFirstArrayKey( _a18 ); + while ( isDefined( _k18 ) ) + { + team = _a18[ _k18 ]; + game[ "menu_changeclass_" + team ] = "changeclass"; + _k18 = getNextArrayKey( _a18, _k18 ); + } + game[ "menu_controls" ] = "ingame_controls"; + game[ "menu_options" ] = "ingame_options"; + game[ "menu_leavegame" ] = "popup_leavegame"; + precachemenu( game[ "menu_controls" ] ); + precachemenu( game[ "menu_options" ] ); + precachemenu( game[ "menu_leavegame" ] ); + precachemenu( "scoreboard" ); + precachemenu( "spectate" ); + precachemenu( game[ "menu_team" ] ); + precachemenu( game[ "menu_changeclass_allies" ] ); + precachemenu( game[ "menu_initteam_allies" ] ); + precachemenu( game[ "menu_changeclass_axis" ] ); + precachemenu( game[ "menu_class" ] ); + precachemenu( game[ "menu_changeclass" ] ); + precachemenu( game[ "menu_initteam_axis" ] ); + precachemenu( game[ "menu_changeclass_offline" ] ); + precachemenu( game[ "menu_changeclass_wager" ] ); + precachemenu( game[ "menu_changeclass_custom" ] ); + precachemenu( game[ "menu_changeclass_barebones" ] ); + precachemenu( game[ "menu_wager_side_bet" ] ); + precachemenu( game[ "menu_wager_side_bet_player" ] ); + precachestring( &"MP_HOST_ENDED_GAME" ); + precachestring( &"MP_HOST_ENDGAME_RESPONSE" ); + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onmenuresponse(); + } +} + +onmenuresponse() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "menuresponse", menu, response ); + if ( response == "back" ) + { + self closemenu(); + self closeingamemenu(); + if ( level.console ) + { + if ( game[ "menu_changeclass" ] != menu && game[ "menu_changeclass_offline" ] != menu || menu == game[ "menu_team" ] && menu == game[ "menu_controls" ] ) + { + if ( isDefined( level.teams[ self.pers[ "team" ] ] ) ) + { + self openmenu( game[ "menu_class" ] ); + } + } + } + continue; + } + else if ( response == "changeteam" && level.allow_teamchange == "1" ) + { + self closemenu(); + self closeingamemenu(); + self openmenu( game[ "menu_team" ] ); + } + if ( response == "changeclass_marines_splitscreen" ) + { + self openmenu( "changeclass_marines_splitscreen" ); + } + if ( response == "changeclass_opfor_splitscreen" ) + { + self openmenu( "changeclass_opfor_splitscreen" ); + } + if ( response == "endgame" ) + { + if ( self issplitscreen() ) + { + level.skipvote = 1; + if ( !level.gameended ) + { + level thread maps/mp/gametypes_zm/_globallogic::forceend(); + } + } + continue; + } + else if ( response == "killserverpc" ) + { + level thread maps/mp/gametypes_zm/_globallogic::killserverpc(); + continue; + } + else if ( response == "endround" ) + { + if ( !level.gameended ) + { + level thread maps/mp/gametypes_zm/_globallogic::forceend(); + } + else + { + self closemenu(); + self closeingamemenu(); + self iprintln( &"MP_HOST_ENDGAME_RESPONSE" ); + } + continue; + } + else if ( menu == game[ "menu_team" ] && level.allow_teamchange == "1" ) + { + switch( response ) + { + case "autoassign": + self [[ level.autoassign ]]( 1 ); + break; + case "spectator": + self [[ level.spectator ]](); + break; + default: + self [[ level.teammenu ]]( response ); + break; + } + continue; + } + else + { + if ( game[ "menu_changeclass" ] != menu && game[ "menu_changeclass_offline" ] != menu && game[ "menu_changeclass_wager" ] != menu || menu == game[ "menu_changeclass_custom" ] && menu == game[ "menu_changeclass_barebones" ] ) + { + self closemenu(); + self closeingamemenu(); + if ( level.rankedmatch && issubstr( response, "custom" ) ) + { + if ( self isitemlocked( maps/mp/gametypes_zm/_rank::getitemindex( "feature_cac" ) ) ) + { + kick( self getentitynumber() ); + } + } + self.selectedclass = 1; + self [[ level.class ]]( response ); + break; + } + else + { + if ( menu == "spectate" ) + { + player = getplayerfromclientnum( int( response ) ); + if ( isDefined( player ) ) + { + self setcurrentspectatorclient( player ); + } + } + } + } + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_perplayer.gsc b/patch_zm/maps/mp/gametypes_zm/_perplayer.gsc new file mode 100644 index 0000000..1fd16a2 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_perplayer.gsc @@ -0,0 +1,196 @@ +#include maps/mp/_utility; + +init( id, playerbegincallback, playerendcallback ) +{ + precacheshader( "objpoint_default" ); + handler = spawnstruct(); + handler.id = id; + handler.playerbegincallback = playerbegincallback; + handler.playerendcallback = playerendcallback; + handler.enabled = 0; + handler.players = []; + thread onplayerconnect( handler ); + level.handlerglobalflagval = 0; + return handler; +} + +enable( handler ) +{ + if ( handler.enabled ) + { + return; + } + handler.enabled = 1; + level.handlerglobalflagval++; + players = get_players(); + i = 0; + while ( i < players.size ) + { + players[ i ].handlerflagval = level.handlerglobalflagval; + i++; + } + players = handler.players; + i = 0; + while ( i < players.size ) + { + if ( players[ i ].handlerflagval != level.handlerglobalflagval ) + { + i++; + continue; + } + else + { + if ( players[ i ].handlers[ handler.id ].ready ) + { + players[ i ] handleplayer( handler ); + } + } + i++; + } +} + +disable( handler ) +{ + if ( !handler.enabled ) + { + return; + } + handler.enabled = 0; + level.handlerglobalflagval++; + players = get_players(); + i = 0; + while ( i < players.size ) + { + players[ i ].handlerflagval = level.handlerglobalflagval; + i++; + } + players = handler.players; + i = 0; + while ( i < players.size ) + { + if ( players[ i ].handlerflagval != level.handlerglobalflagval ) + { + i++; + continue; + } + else + { + if ( players[ i ].handlers[ handler.id ].ready ) + { + players[ i ] unhandleplayer( handler, 0, 0 ); + } + } + i++; + } +} + +onplayerconnect( handler ) +{ + for ( ;; ) + { + level waittill( "connecting", player ); + if ( !isDefined( player.handlers ) ) + { + player.handlers = []; + } + player.handlers[ handler.id ] = spawnstruct(); + player.handlers[ handler.id ].ready = 0; + player.handlers[ handler.id ].handled = 0; + player.handlerflagval = -1; + handler.players[ handler.players.size ] = player; + player thread onplayerdisconnect( handler ); + player thread onplayerspawned( handler ); + player thread onjoinedteam( handler ); + player thread onjoinedspectators( handler ); + player thread onplayerkilled( handler ); + } +} + +onplayerdisconnect( handler ) +{ + self waittill( "disconnect" ); + newplayers = []; + i = 0; + while ( i < handler.players.size ) + { + if ( handler.players[ i ] != self ) + { + newplayers[ newplayers.size ] = handler.players[ i ]; + } + i++; + } + handler.players = newplayers; + self thread unhandleplayer( handler, 1, 1 ); +} + +onjoinedteam( handler ) +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_team" ); + self thread unhandleplayer( handler, 1, 0 ); + } +} + +onjoinedspectators( handler ) +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_spectators" ); + self thread unhandleplayer( handler, 1, 0 ); + } +} + +onplayerspawned( handler ) +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread handleplayer( handler ); + } +} + +onplayerkilled( handler ) +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "killed_player" ); + self thread unhandleplayer( handler, 1, 0 ); + } +} + +handleplayer( handler ) +{ + self.handlers[ handler.id ].ready = 1; + if ( !handler.enabled ) + { + return; + } + if ( self.handlers[ handler.id ].handled ) + { + return; + } + self.handlers[ handler.id ].handled = 1; + self thread [[ handler.playerbegincallback ]](); +} + +unhandleplayer( handler, unsetready, disconnected ) +{ + if ( !disconnected && unsetready ) + { + self.handlers[ handler.id ].ready = 0; + } + if ( !self.handlers[ handler.id ].handled ) + { + return; + } + if ( !disconnected ) + { + self.handlers[ handler.id ].handled = 0; + } + self thread [[ handler.playerendcallback ]]( disconnected ); +} diff --git a/patch_zm/maps/mp/gametypes_zm/_serversettings.gsc b/patch_zm/maps/mp/gametypes_zm/_serversettings.gsc new file mode 100644 index 0000000..a747dcc --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_serversettings.gsc @@ -0,0 +1,207 @@ + +init() +{ + level.hostname = getDvar( "sv_hostname" ); + if ( level.hostname == "" ) + { + level.hostname = "CoDHost"; + } + setdvar( "sv_hostname", level.hostname ); + setdvar( "ui_hostname", level.hostname ); + makedvarserverinfo( "ui_hostname", "CoDHost" ); + level.motd = getDvar( "scr_motd" ); + if ( level.motd == "" ) + { + level.motd = ""; + } + setdvar( "scr_motd", level.motd ); + setdvar( "ui_motd", level.motd ); + makedvarserverinfo( "ui_motd", "" ); + level.allowvote = getDvar( "g_allowVote" ); + if ( level.allowvote == "" ) + { + level.allowvote = "1"; + } + setdvar( "g_allowvote", level.allowvote ); + setdvar( "ui_allowvote", level.allowvote ); + makedvarserverinfo( "ui_allowvote", "1" ); + level.allow_teamchange = "0"; + if ( sessionmodeisprivate() || !sessionmodeisonlinegame() ) + { + level.allow_teamchange = "1"; + } + setdvar( "ui_allow_teamchange", level.allow_teamchange ); + level.friendlyfire = getgametypesetting( "friendlyfiretype" ); + setdvar( "ui_friendlyfire", level.friendlyfire ); + makedvarserverinfo( "ui_friendlyfire", "0" ); + if ( getDvar( "scr_mapsize" ) == "" ) + { + setdvar( "scr_mapsize", "64" ); + } + else if ( getDvarFloat( "scr_mapsize" ) >= 64 ) + { + setdvar( "scr_mapsize", "64" ); + } + else if ( getDvarFloat( "scr_mapsize" ) >= 32 ) + { + setdvar( "scr_mapsize", "32" ); + } + else if ( getDvarFloat( "scr_mapsize" ) >= 16 ) + { + setdvar( "scr_mapsize", "16" ); + } + else + { + setdvar( "scr_mapsize", "8" ); + } + level.mapsize = getDvarFloat( "scr_mapsize" ); + constraingametype( getDvar( "g_gametype" ) ); + constrainmapsize( level.mapsize ); + for ( ;; ) + { + updateserversettings(); + wait 5; + } +} + +updateserversettings() +{ + sv_hostname = getDvar( "sv_hostname" ); + if ( level.hostname != sv_hostname ) + { + level.hostname = sv_hostname; + setdvar( "ui_hostname", level.hostname ); + } + scr_motd = getDvar( "scr_motd" ); + if ( level.motd != scr_motd ) + { + level.motd = scr_motd; + setdvar( "ui_motd", level.motd ); + } + g_allowvote = getDvar( "g_allowVote" ); + if ( level.allowvote != g_allowvote ) + { + level.allowvote = g_allowvote; + setdvar( "ui_allowvote", level.allowvote ); + } + scr_friendlyfire = getgametypesetting( "friendlyfiretype" ); + if ( level.friendlyfire != scr_friendlyfire ) + { + level.friendlyfire = scr_friendlyfire; + setdvar( "ui_friendlyfire", level.friendlyfire ); + } +} + +constraingametype( gametype ) +{ + entities = getentarray(); + i = 0; + while ( i < entities.size ) + { + entity = entities[ i ]; + if ( gametype == "dm" ) + { + if ( isDefined( entity.script_gametype_dm ) && entity.script_gametype_dm != "1" ) + { + entity delete(); + } + i++; + continue; + } + else if ( gametype == "tdm" ) + { + if ( isDefined( entity.script_gametype_tdm ) && entity.script_gametype_tdm != "1" ) + { + entity delete(); + } + i++; + continue; + } + else if ( gametype == "ctf" ) + { + if ( isDefined( entity.script_gametype_ctf ) && entity.script_gametype_ctf != "1" ) + { + entity delete(); + } + i++; + continue; + } + else if ( gametype == "hq" ) + { + if ( isDefined( entity.script_gametype_hq ) && entity.script_gametype_hq != "1" ) + { + entity delete(); + } + i++; + continue; + } + else if ( gametype == "sd" ) + { + if ( isDefined( entity.script_gametype_sd ) && entity.script_gametype_sd != "1" ) + { + entity delete(); + } + i++; + continue; + } + else + { + if ( gametype == "koth" ) + { + if ( isDefined( entity.script_gametype_koth ) && entity.script_gametype_koth != "1" ) + { + entity delete(); + } + } + } + i++; + } +} + +constrainmapsize( mapsize ) +{ + entities = getentarray(); + i = 0; + while ( i < entities.size ) + { + entity = entities[ i ]; + if ( int( mapsize ) == 8 ) + { + if ( isDefined( entity.script_mapsize_08 ) && entity.script_mapsize_08 != "1" ) + { + entity delete(); + } + i++; + continue; + } + else if ( int( mapsize ) == 16 ) + { + if ( isDefined( entity.script_mapsize_16 ) && entity.script_mapsize_16 != "1" ) + { + entity delete(); + } + i++; + continue; + } + else if ( int( mapsize ) == 32 ) + { + if ( isDefined( entity.script_mapsize_32 ) && entity.script_mapsize_32 != "1" ) + { + entity delete(); + } + i++; + continue; + } + else + { + if ( int( mapsize ) == 64 ) + { + if ( isDefined( entity.script_mapsize_64 ) && entity.script_mapsize_64 != "1" ) + { + entity delete(); + } + } + } + i++; + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_spawning.gsc b/patch_zm/maps/mp/gametypes_zm/_spawning.gsc new file mode 100644 index 0000000..ce29a09 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_spawning.gsc @@ -0,0 +1,1073 @@ +#include maps/mp/gametypes_zm/_spawnlogic; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + if ( !isDefined( level.gamemodespawndvars ) ) + { + level.gamemodespawndvars = ::default_gamemodespawndvars; + } + level init_spawn_system(); + level.recently_deceased = []; + _a74 = level.teams; + _k74 = getFirstArrayKey( _a74 ); + while ( isDefined( _k74 ) ) + { + team = _a74[ _k74 ]; + level.recently_deceased[ team ] = spawn_array_struct(); + _k74 = getNextArrayKey( _a74, _k74 ); + } + level thread onplayerconnect(); + if ( getDvar( #"AD6C19FE" ) == "" ) + { + level.spawn_visibility_check_max = 20; + } + else + { + level.spawn_visibility_check_max = getDvarInt( #"AD6C19FE" ); + } + level.spawnprotectiontime = getgametypesetting( "spawnprotectiontime" ); +/# + setdvar( "scr_debug_spawn_player", "" ); + setdvar( "scr_debug_render_spawn_data", "1" ); + setdvar( "scr_debug_render_snapshotmode", "0" ); + setdvar( "scr_spawn_point_test_mode", "0" ); + level.test_spawn_point_index = 0; + setdvar( "scr_debug_render_spawn_text", "1" ); +#/ + return; +} + +default_gamemodespawndvars( reset_dvars ) +{ +} + +init_spawn_system() +{ + level.spawnsystem = spawnstruct(); + spawnsystem = level.spawnsystem; + level get_player_spawning_dvars( 1 ); + level thread initialize_player_spawning_dvars(); + spawnsystem.einfluencer_shape_sphere = 0; + spawnsystem.einfluencer_shape_cylinder = 1; + spawnsystem.einfluencer_type_normal = 0; + spawnsystem.einfluencer_type_player = 1; + spawnsystem.einfluencer_type_weapon = 2; + spawnsystem.einfluencer_type_dog = 3; + spawnsystem.einfluencer_type_vehicle = 4; + spawnsystem.einfluencer_type_game_mode = 6; + spawnsystem.einfluencer_type_enemy_spawned = 7; + spawnsystem.einfluencer_curve_constant = 0; + spawnsystem.einfluencer_curve_linear = 1; + spawnsystem.einfluencer_curve_steep = 2; + spawnsystem.einfluencer_curve_inverse_linear = 3; + spawnsystem.einfluencer_curve_negative_to_positive = 4; + spawnsystem.ispawn_teammask = []; + spawnsystem.ispawn_teammask_free = 1; + spawnsystem.ispawn_teammask[ "free" ] = spawnsystem.ispawn_teammask_free; + all = spawnsystem.ispawn_teammask_free; + count = 1; + _a146 = level.teams; + _k146 = getFirstArrayKey( _a146 ); + while ( isDefined( _k146 ) ) + { + team = _a146[ _k146 ]; + spawnsystem.ispawn_teammask[ team ] = 1 << count; + all |= spawnsystem.ispawn_teammask[ team ]; + count++; + _k146 = getNextArrayKey( _a146, _k146 ); + } + spawnsystem.ispawn_teammask[ "all" ] = all; +} + +onplayerconnect() +{ + level endon( "game_ended" ); + for ( ;; ) + { + level waittill( "connecting", player ); + player setentertime( getTime() ); + player thread onplayerspawned(); + player thread ondisconnect(); + player thread onteamchange(); + player thread ongrenadethrow(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread initialspawnprotection( "specialty_nottargetedbyairsupport", 1 ); + self thread initialspawnprotection( "specialty_nokillstreakreticle", 0 ); + self thread initialspawnprotection( "specialty_nottargettedbysentry", 0 ); + if ( isDefined( self.pers[ "hasRadar" ] ) && self.pers[ "hasRadar" ] ) + { + self.hasspyplane = 1; + } + self enable_player_influencers( 1 ); + self thread ondeath(); + } +} + +ondeath() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + self waittill( "death" ); + self enable_player_influencers( 0 ); + self create_body_influencers(); +} + +onteamchange() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + while ( 1 ) + { + self waittill( "joined_team" ); + self player_influencers_set_team(); + wait 0,05; + } +} + +ongrenadethrow() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + while ( 1 ) + { + self waittill( "grenade_fire", grenade, weaponname ); + level thread create_grenade_influencers( self.pers[ "team" ], weaponname, grenade ); + wait 0,05; + } +} + +ondisconnect() +{ + level endon( "game_ended" ); + self waittill( "disconnect" ); +} + +get_score_curve_index( curve ) +{ + switch( curve ) + { + case "linear": + return level.spawnsystem.einfluencer_curve_linear; + case "steep": + return level.spawnsystem.einfluencer_curve_steep; + case "inverse_linear": + return level.spawnsystem.einfluencer_curve_linear; + case "negative_to_positive": + return level.spawnsystem.einfluencer_curve_negative_to_positive; + case "constant": + default: + return level.spawnsystem.einfluencer_curve_constant; + } +} + +get_influencer_type_index( curve ) +{ +} + +create_player_influencers() +{ +/# + assert( !isDefined( self.influencer_enemy_sphere ) ); +#/ +/# + assert( !isDefined( self.influencer_weapon_cylinder ) ); +#/ +/# + if ( level.teambased ) + { + assert( !isDefined( self.influencer_friendly_sphere ) ); + } +#/ +/# + if ( level.teambased ) + { + assert( !isDefined( self.influencer_friendly_cylinder ) ); + } +#/ + if ( !level.teambased ) + { + team_mask = level.spawnsystem.ispawn_teammask_free; + other_team_mask = level.spawnsystem.ispawn_teammask_free; + weapon_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else if ( isDefined( self.pers[ "team" ] ) ) + { + team = self.pers[ "team" ]; + team_mask = getteammask( team ); + other_team_mask = getotherteamsmask( team ); + weapon_team_mask = getotherteamsmask( team ); + } + else + { + team_mask = 0; + other_team_mask = 0; + weapon_team_mask = 0; + } + if ( level.hardcoremode ) + { + weapon_team_mask |= team_mask; + } + angles = self.angles; + origin = self.origin; + up = ( 0, 0, 0 ); + forward = ( 0, 0, 0 ); + cylinder_forward = up; + cylinder_up = forward; + self.influencer_enemy_sphere = addsphereinfluencer( level.spawnsystem.einfluencer_type_player, origin, level.spawnsystem.enemy_influencer_radius, level.spawnsystem.enemy_influencer_score, other_team_mask, "enemy,r,s", get_score_curve_index( level.spawnsystem.enemy_influencer_score_curve ), 0, self ); + if ( level.teambased ) + { + cylinder_up = -1 * forward; + self.influencer_friendly_sphere = addsphereinfluencer( level.spawnsystem.einfluencer_type_player, origin, level.spawnsystem.friend_weak_influencer_radius, level.spawnsystem.friend_weak_influencer_score, team_mask, "friend_weak,r,s", get_score_curve_index( level.spawnsystem.friend_weak_influencer_score_curve ), 0, self ); + } + self.spawn_influencers_created = 1; + if ( !isDefined( self.pers[ "team" ] ) || self.pers[ "team" ] == "spectator" ) + { + self enable_player_influencers( 0 ); + } +} + +remove_player_influencers() +{ + if ( level.teambased && isDefined( self.influencer_friendly_sphere ) ) + { + removeinfluencer( self.influencer_friendly_sphere ); + self.influencer_friendly_sphere = undefined; + } + if ( level.teambased && isDefined( self.influencer_friendly_cylinder ) ) + { + removeinfluencer( self.influencer_friendly_cylinder ); + self.influencer_friendly_cylinder = undefined; + } + if ( isDefined( self.influencer_enemy_sphere ) ) + { + removeinfluencer( self.influencer_enemy_sphere ); + self.influencer_enemy_sphere = undefined; + } + if ( isDefined( self.influencer_weapon_cylinder ) ) + { + removeinfluencer( self.influencer_weapon_cylinder ); + self.influencer_weapon_cylinder = undefined; + } +} + +enable_player_influencers( enabled ) +{ + if ( !isDefined( self.spawn_influencers_created ) ) + { + self create_player_influencers(); + } + if ( isDefined( self.influencer_friendly_sphere ) ) + { + enableinfluencer( self.influencer_friendly_sphere, enabled ); + } + if ( isDefined( self.influencer_friendly_cylinder ) ) + { + enableinfluencer( self.influencer_friendly_cylinder, enabled ); + } + if ( isDefined( self.influencer_enemy_sphere ) ) + { + enableinfluencer( self.influencer_enemy_sphere, enabled ); + } + if ( isDefined( self.influencer_weapon_cylinder ) ) + { + enableinfluencer( self.influencer_weapon_cylinder, enabled ); + } +} + +player_influencers_set_team() +{ + if ( !level.teambased ) + { + team_mask = level.spawnsystem.ispawn_teammask_free; + other_team_mask = level.spawnsystem.ispawn_teammask_free; + weapon_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + team = self.pers[ "team" ]; + team_mask = getteammask( team ); + other_team_mask = getotherteamsmask( team ); + weapon_team_mask = getotherteamsmask( team ); + } + if ( level.friendlyfire != 0 && level.teambased ) + { + weapon_team_mask |= team_mask; + } + if ( isDefined( self.influencer_friendly_sphere ) ) + { + setinfluencerteammask( self.influencer_friendly_sphere, team_mask ); + } + if ( isDefined( self.influencer_friendly_cylinder ) ) + { + setinfluencerteammask( self.influencer_friendly_cylinder, team_mask ); + } + if ( isDefined( self.influencer_enemy_sphere ) ) + { + setinfluencerteammask( self.influencer_enemy_sphere, other_team_mask ); + } + if ( isDefined( self.influencer_weapon_cylinder ) ) + { + setinfluencerteammask( self.influencer_weapon_cylinder, weapon_team_mask ); + } +} + +create_body_influencers() +{ + if ( level.teambased ) + { + team_mask = getteammask( self.pers[ "team" ] ); + } + else + { + team_mask = level.spawnsystem.ispawn_teammask_free; + } + addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, self.origin, level.spawnsystem.dead_friend_influencer_radius, level.spawnsystem.dead_friend_influencer_score, team_mask, "dead_friend,r,s", get_score_curve_index( level.spawnsystem.dead_friend_influencer_score_curve ), level.spawnsystem.dead_friend_influencer_timeout_seconds ); +} + +create_grenade_influencers( parent_team, weaponname, grenade ) +{ + pixbeginevent( "create_grenade_influencers" ); + if ( !level.teambased ) + { + weapon_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + weapon_team_mask = getotherteamsmask( parent_team ); + if ( level.friendlyfire ) + { + weapon_team_mask |= getteammask( parent_team ); + } + } + if ( issubstr( weaponname, "napalmblob" ) || issubstr( weaponname, "gl_" ) ) + { + pixendevent(); + return; + } + timeout = 0; + if ( weaponname == "tabun_gas_mp" ) + { + timeout = 7; + } + if ( isDefined( grenade.origin ) ) + { + if ( weaponname == "claymore_mp" || weaponname == "bouncingbetty_mp" ) + { + addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, grenade.origin, level.spawnsystem.claymore_influencer_radius, level.spawnsystem.claymore_influencer_score, weapon_team_mask, "claymore,r,s", get_score_curve_index( level.spawnsystem.claymore_influencer_score_curve ), timeout, grenade ); + } + else + { + addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, grenade.origin, level.spawnsystem.grenade_influencer_radius, level.spawnsystem.grenade_influencer_score, weapon_team_mask, "grenade,r,s", get_score_curve_index( level.spawnsystem.grenade_influencer_score_curve ), timeout, grenade ); + } + } + pixendevent(); +} + +create_napalm_fire_influencers( point, direction, parent_team, duration ) +{ + timeout = duration; + weapon_team_mask = 0; + offset = vectorScale( anglesToForward( direction ), 1100 ); + addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, point + ( 2 * offset ), level.spawnsystem.napalm_influencer_radius, level.spawnsystem.napalm_influencer_score, weapon_team_mask, "napalm,r,s", get_score_curve_index( level.spawnsystem.napalm_influencer_score_curve ), timeout ); + addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, point + offset, level.spawnsystem.napalm_influencer_radius, level.spawnsystem.napalm_influencer_score, weapon_team_mask, "napalm,r,s", get_score_curve_index( level.spawnsystem.napalm_influencer_score_curve ), timeout ); + addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, point, level.spawnsystem.napalm_influencer_radius, level.spawnsystem.napalm_influencer_score, weapon_team_mask, "napalm,r,s", get_score_curve_index( level.spawnsystem.napalm_influencer_score_curve ), timeout ); + addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, point - offset, level.spawnsystem.napalm_influencer_radius, level.spawnsystem.napalm_influencer_score, weapon_team_mask, "napalm,r,s", get_score_curve_index( level.spawnsystem.napalm_influencer_score_curve ), timeout ); +} + +create_auto_turret_influencer( point, parent_team, angles ) +{ + if ( !level.teambased ) + { + weapon_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + weapon_team_mask = getotherteamsmask( parent_team ); + } + projected_point = point + vectorScale( anglesToForward( angles ), level.spawnsystem.auto_turret_influencer_radius * 0,7 ); + influencerid = addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, projected_point, level.spawnsystem.auto_turret_influencer_radius, level.spawnsystem.auto_turret_influencer_score, weapon_team_mask, "auto_turret,r,s", get_score_curve_index( level.spawnsystem.auto_turret_influencer_score_curve ) ); + return influencerid; +} + +create_dog_influencers() +{ + if ( !level.teambased ) + { + dog_enemy_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + dog_enemy_team_mask = getotherteamsmask( self.aiteam ); + } + addsphereinfluencer( level.spawnsystem.einfluencer_type_dog, self.origin, level.spawnsystem.dog_influencer_radius, level.spawnsystem.dog_influencer_score, dog_enemy_team_mask, "dog,r,s", get_score_curve_index( level.spawnsystem.dog_influencer_score_curve ), 0, self ); +} + +create_helicopter_influencers( parent_team ) +{ + if ( !level.teambased ) + { + team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + team_mask = getotherteamsmask( parent_team ); + } + self.influencer_helicopter_cylinder = addcylinderinfluencer( level.spawnsystem.einfluencer_type_normal, self.origin, ( 0, 0, 0 ), ( 0, 0, 0 ), level.spawnsystem.helicopter_influencer_radius, level.spawnsystem.helicopter_influencer_length, level.spawnsystem.helicopter_influencer_score, team_mask, "helicopter,r,s", get_score_curve_index( level.spawnsystem.helicopter_influencer_score_curve ), 0, self ); +} + +remove_helicopter_influencers() +{ + if ( isDefined( self.influencer_helicopter_cylinder ) ) + { + removeinfluencer( self.influencer_helicopter_cylinder ); + } + self.influencer_helicopter_cylinder = undefined; +} + +create_tvmissile_influencers( parent_team ) +{ + if ( !level.teambased || is_hardcore() ) + { + team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + team_mask = getotherteamsmask( parent_team ); + } + self.influencer_tvmissile_cylinder = addcylinderinfluencer( level.spawnsystem.einfluencer_type_normal, self.origin, ( 0, 0, 0 ), ( 0, 0, 0 ), level.spawnsystem.tvmissile_influencer_radius, level.spawnsystem.tvmissile_influencer_length, level.spawnsystem.tvmissile_influencer_score, team_mask, "tvmissile,r,s", get_score_curve_index( level.spawnsystem.tvmissile_influencer_score_curve ), 0, self ); +} + +remove_tvmissile_influencers() +{ + if ( isDefined( self.influencer_tvmissile_cylinder ) ) + { + removeinfluencer( self.influencer_tvmissile_cylinder ); + } + self.influencer_tvmissile_cylinder = undefined; +} + +create_artillery_influencers( point, radius ) +{ + weapon_team_mask = 0; + if ( radius < 0 ) + { + thisradius = level.spawnsystem.artillery_influencer_radius; + } + else + { + thisradius = radius; + } + return addcylinderinfluencer( level.spawnsystem.einfluencer_type_normal, point + vectorScale( ( 0, 0, 0 ), 2000 ), ( 0, 0, 0 ), ( 0, 0, 0 ), thisradius, 5000, level.spawnsystem.artillery_influencer_score, weapon_team_mask, "artillery,s,r", get_score_curve_index( level.spawnsystem.artillery_influencer_score_curve ), 7 ); +} + +create_vehicle_influencers() +{ + weapon_team_mask = 0; + vehicleradius = 144; + cylinderlength = level.spawnsystem.vehicle_influencer_lead_seconds; + up = ( 0, 0, 0 ); + forward = ( 0, 0, 0 ); + cylinder_forward = up; + cylinder_up = forward; + return addcylinderinfluencer( level.spawnsystem.einfluencer_type_vehicle, self.origin, cylinder_forward, cylinder_up, vehicleradius, cylinderlength, level.spawnsystem.vehicle_influencer_score, weapon_team_mask, "vehicle,s", get_score_curve_index( level.spawnsystem.vehicle_influencer_score_curve ), 0, self ); +} + +create_rcbomb_influencers( team ) +{ + if ( !level.teambased ) + { + other_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + other_team_mask = getotherteamsmask( team ); + } + return addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, self.origin, level.spawnsystem.rcbomb_influencer_radius, level.spawnsystem.rcbomb_influencer_score, other_team_mask, "rcbomb,r,s", get_score_curve_index( level.spawnsystem.rcbomb_influencer_score_curve ), 0, self ); +} + +create_qrdrone_influencers( team ) +{ + if ( !level.teambased ) + { + other_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + other_team_mask = getotherteamsmask( team ); + } + self.influencer_qrdrone_cylinder = addcylinderinfluencer( level.spawnsystem.einfluencer_type_normal, self.origin, ( 0, 0, 0 ), ( 0, 0, 0 ), level.spawnsystem.qrdrone_cylinder_influencer_radius, level.spawnsystem.qrdrone_cylinder_influencer_length, level.spawnsystem.qrdrone_cylinder_influencer_score, other_team_mask, "qrdrone_cyl,r,s", get_score_curve_index( level.spawnsystem.qrdrone_cylinder_influencer_score_curve ), 0, self ); + return addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, self.origin, level.spawnsystem.qrdrone_influencer_radius, level.spawnsystem.qrdrone_influencer_score, other_team_mask, "qrdrone,r,s", get_score_curve_index( level.spawnsystem.qrdrone_influencer_score_curve ), 0, self ); +} + +create_aitank_influencers( team ) +{ + if ( !level.teambased ) + { + other_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + other_team_mask = getotherteamsmask( team ); + } + return addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, self.origin, level.spawnsystem.aitank_influencer_radius, level.spawnsystem.aitank_influencer_score, other_team_mask, "aitank,r,s", get_score_curve_index( level.spawnsystem.aitank_influencer_score_curve ), 0, self ); +} + +create_pegasus_influencer( origin, team ) +{ + if ( !level.teambased ) + { + other_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + other_team_mask = getotherteamsmask( team ); + } + return addsphereinfluencer( level.spawnsystem.einfluencer_type_normal, origin, level.spawnsystem.pegasus_influencer_radius, level.spawnsystem.pegasus_influencer_score, other_team_mask, "pegasus,r,s", get_score_curve_index( level.spawnsystem.pegasus_influencer_score_curve ), 0 ); +} + +create_map_placed_influencers() +{ + staticinfluencerents = getentarray( "mp_uspawn_influencer", "classname" ); + i = 0; + while ( i < staticinfluencerents.size ) + { + staticinfluencerent = staticinfluencerents[ i ]; + if ( isDefined( staticinfluencerent.script_gameobjectname ) && staticinfluencerent.script_gameobjectname == "twar" ) + { + i++; + continue; + } + else + { + create_map_placed_influencer( staticinfluencerent ); + } + i++; + } +} + +create_map_placed_influencer( influencer_entity, optional_score_override ) +{ + influencer_id = -1; + if ( isDefined( influencer_entity.script_shape ) && isDefined( influencer_entity.script_score ) && isDefined( influencer_entity.script_score_curve ) ) + { + switch( influencer_entity.script_shape ) + { + case "sphere": + if ( isDefined( influencer_entity.radius ) ) + { + if ( isDefined( optional_score_override ) ) + { + score = optional_score_override; + } + else + { + score = influencer_entity.script_score; + } + influencer_id = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, influencer_entity.origin, influencer_entity.radius, score, getteammask( influencer_entity.script_team ), "*map_defined", get_score_curve_index( influencer_entity.script_score_curve ) ); + } + else + { +/# + assertmsg( "Radiant-placed sphere spawn influencers require 'radius' parameter" ); +#/ + } + break; + case "cylinder": + if ( isDefined( influencer_entity.radius ) && isDefined( influencer_entity.height ) ) + { + if ( isDefined( optional_score_override ) ) + { + score = optional_score_override; + } + else + { + score = influencer_entity.script_score; + } + influencer_id = addcylinderinfluencer( level.spawnsystem.einfluencer_type_game_mode, influencer_entity.origin, anglesToForward( influencer_entity.angles ), anglesToUp( influencer_entity.angles ), influencer_entity.radius, influencer_entity.height, score, getteammask( influencer_entity.script_team ), "*map_defined", get_score_curve_index( influencer_entity.script_score_curve ) ); + } + else + { +/# + assertmsg( "Radiant-placed cylinder spawn influencers require 'radius' and 'height' parameters" ); +#/ + } + break; + default: +/# + assertmsg( "Unsupported script_shape value ("" + influencer_entity.script_shape + "") for unified spawning system static influencer. Supported shapes are "cylinder" and "sphere"." ); +#/ + break; + } + } + else + { +/# + assertmsg( "Radiant-placed spawn influencers require 'script_shape', 'script_score' and 'script_score_curve' parameters" ); +#/ + } + return influencer_id; +} + +create_enemy_spawned_influencers( origin, team ) +{ + if ( !level.teambased ) + { + other_team_mask = level.spawnsystem.ispawn_teammask_free; + } + else + { + other_team_mask = getotherteamsmask( team ); + } + return addsphereinfluencer( level.spawnsystem.einfluencer_type_enemy_spawned, origin, level.spawnsystem.enemy_spawned_influencer_radius, level.spawnsystem.enemy_spawned_influencer_score, other_team_mask, "enemy_spawned,r,s", get_score_curve_index( level.spawnsystem.enemy_spawned_influencer_score_curve ), 7 ); +} + +updateallspawnpoints() +{ + _a1046 = level.teams; + _k1046 = getFirstArrayKey( _a1046 ); + while ( isDefined( _k1046 ) ) + { + team = _a1046[ _k1046 ]; + gatherspawnentities( team ); + _k1046 = getNextArrayKey( _a1046, _k1046 ); + } + clearspawnpoints(); + if ( level.teambased ) + { + _a1055 = level.teams; + _k1055 = getFirstArrayKey( _a1055 ); + while ( isDefined( _k1055 ) ) + { + team = _a1055[ _k1055 ]; + addspawnpoints( team, level.unified_spawn_points[ team ].a ); + _k1055 = getNextArrayKey( _a1055, _k1055 ); + } + } + else _a1062 = level.teams; + _k1062 = getFirstArrayKey( _a1062 ); + while ( isDefined( _k1062 ) ) + { + team = _a1062[ _k1062 ]; + addspawnpoints( "free", level.unified_spawn_points[ team ].a ); + _k1062 = getNextArrayKey( _a1062, _k1062 ); + } + remove_unused_spawn_entities(); +} + +initialize_player_spawning_dvars() +{ +/# + reset_dvars = 1; + while ( 1 ) + { + get_player_spawning_dvars( reset_dvars ); + reset_dvars = 0; + wait 2; +#/ + } +} + +get_player_spawning_dvars( reset_dvars ) +{ + k_player_height = get_player_height(); + player_height_times_10 = "" + ( 10 * k_player_height ); + ss = level.spawnsystem; + player_influencer_radius = 15 * k_player_height; + player_influencer_score = 150; + dog_influencer_radius = 10 * k_player_height; + dog_influencer_score = 150; + ss.script_based_influencer_system = set_dvar_int_if_unset( "scr_script_based_influencer_system", "0", reset_dvars ); + ss.randomness_range = set_dvar_float_if_unset( "scr_spawn_randomness_range", "10", reset_dvars ); + ss.objective_facing_bonus = set_dvar_float_if_unset( "scr_spawn_objective_facing_bonus", "50", reset_dvars ); + ss.friend_weak_influencer_score = set_dvar_float_if_unset( "scr_spawn_friend_weak_influencer_score", "10", reset_dvars ); + ss.friend_weak_influencer_score_curve = set_dvar_if_unset( "scr_spawn_friend_weak_influencer_score_curve", "steep", reset_dvars ); + ss.friend_weak_influencer_radius = set_dvar_float_if_unset( "scr_spawn_friend_weak_influencer_radius", player_height_times_10, reset_dvars ); + ss.enemy_influencer_score = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_score", "-150", reset_dvars ); + ss.enemy_influencer_score_curve = set_dvar_if_unset( "scr_spawn_enemy_influencer_score_curve", "steep", reset_dvars ); + ss.enemy_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_influencer_radius", "2600", reset_dvars ); + ss.dead_friend_influencer_timeout_seconds = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_timeout_seconds", "15", reset_dvars ); + ss.dead_friend_influencer_count = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_count", "7", reset_dvars ); + ss.dead_friend_influencer_score = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_score", "-100", reset_dvars ); + ss.dead_friend_influencer_score_curve = set_dvar_if_unset( "scr_spawn_dead_friend_influencer_score_curve", "steep", reset_dvars ); + ss.dead_friend_influencer_radius = set_dvar_float_if_unset( "scr_spawn_dead_friend_influencer_radius", player_height_times_10, reset_dvars ); + ss.vehicle_influencer_score = set_dvar_float_if_unset( "scr_spawn_vehicle_influencer_score", "-50", reset_dvars ); + ss.vehicle_influencer_score_curve = set_dvar_if_unset( "scr_spawn_vehicle_influencer_score_curve", "linear", reset_dvars ); + ss.vehicle_influencer_lead_seconds = set_dvar_float_if_unset( "scr_spawn_vehicle_influencer_lead_seconds", "3", reset_dvars ); + ss.dog_influencer_score = set_dvar_float_if_unset( "scr_spawn_dog_influencer_score", "-150", reset_dvars ); + ss.dog_influencer_score_curve = set_dvar_if_unset( "scr_spawn_dog_influencer_score_curve", "steep", reset_dvars ); + ss.dog_influencer_radius = set_dvar_float_if_unset( "scr_spawn_dog_influencer_radius", "" + ( 15 * k_player_height ), reset_dvars ); + ss.artillery_influencer_score = set_dvar_float_if_unset( "scr_spawn_artillery_influencer_score", "-600", reset_dvars ); + ss.artillery_influencer_score_curve = set_dvar_if_unset( "scr_spawn_artillery_influencer_score_curve", "linear", reset_dvars ); + ss.artillery_influencer_radius = set_dvar_float_if_unset( "scr_spawn_artillery_influencer_radius", "1200", reset_dvars ); + ss.grenade_influencer_score = set_dvar_float_if_unset( "scr_spawn_grenade_influencer_score", "-300", reset_dvars ); + ss.grenade_influencer_score_curve = set_dvar_if_unset( "scr_spawn_grenade_influencer_score_curve", "linear", reset_dvars ); + ss.grenade_influencer_radius = set_dvar_float_if_unset( "scr_spawn_grenade_influencer_radius", "" + ( 8 * k_player_height ), reset_dvars ); + ss.grenade_endpoint_influencer_score = set_dvar_float_if_unset( "scr_spawn_grenade_endpoint_influencer_score", "-300", reset_dvars ); + ss.grenade_endpoint_influencer_score_curve = set_dvar_if_unset( "scr_spawn_grenade_endpoint_influencer_score_curve", "linear", reset_dvars ); + ss.grenade_endpoint_influencer_radius = set_dvar_float_if_unset( "scr_spawn_grenade_endpoint_influencer_radius", "" + ( 8 * k_player_height ), reset_dvars ); + ss.claymore_influencer_score = set_dvar_float_if_unset( "scr_spawn_claymore_influencer_score", "-150", reset_dvars ); + ss.claymore_influencer_score_curve = set_dvar_if_unset( "scr_spawn_claymore_influencer_score_curve", "steep", reset_dvars ); + ss.claymore_influencer_radius = set_dvar_float_if_unset( "scr_spawn_claymore_influencer_radius", "" + ( 9 * k_player_height ), reset_dvars ); + ss.napalm_influencer_score = set_dvar_float_if_unset( "scr_spawn_napalm_influencer_score", "-500", reset_dvars ); + ss.napalm_influencer_score_curve = set_dvar_if_unset( "scr_spawn_napalm_influencer_score_curve", "linear", reset_dvars ); + ss.napalm_influencer_radius = set_dvar_float_if_unset( "scr_spawn_napalm_influencer_radius", "" + 750, reset_dvars ); + ss.auto_turret_influencer_score = set_dvar_float_if_unset( "scr_spawn_auto_turret_influencer_score", "-650", reset_dvars ); + ss.auto_turret_influencer_score_curve = set_dvar_if_unset( "scr_spawn_auto_turret_influencer_score_curve", "linear", reset_dvars ); + ss.auto_turret_influencer_radius = set_dvar_float_if_unset( "scr_spawn_auto_turret_influencer_radius", "" + 1200, reset_dvars ); + ss.rcbomb_influencer_score = set_dvar_float_if_unset( "scr_spawn_rcbomb_influencer_score", "-200", reset_dvars ); + ss.rcbomb_influencer_score_curve = set_dvar_if_unset( "scr_spawn_rcbomb_influencer_score_curve", "steep", reset_dvars ); + ss.rcbomb_influencer_radius = set_dvar_float_if_unset( "scr_spawn_rcbomb_influencer_radius", "" + ( 25 * k_player_height ), reset_dvars ); + ss.qrdrone_influencer_score = set_dvar_float_if_unset( "scr_spawn_qrdrone_influencer_score", "-200", reset_dvars ); + ss.qrdrone_influencer_score_curve = set_dvar_if_unset( "scr_spawn_qrdrone_influencer_score_curve", "steep", reset_dvars ); + ss.qrdrone_influencer_radius = set_dvar_float_if_unset( "scr_spawn_qrdrone_influencer_radius", "" + ( 25 * k_player_height ), reset_dvars ); + ss.qrdrone_cylinder_influencer_score = set_dvar_float_if_unset( "scr_spawn_qrdrone_cylinder_influencer_score", "-300", reset_dvars ); + ss.qrdrone_cylinder_influencer_score_curve = set_dvar_if_unset( "scr_spawn_qrdrone_cylinder_influencer_score_curve", "linear", reset_dvars ); + ss.qrdrone_cylinder_influencer_radius = set_dvar_float_if_unset( "scr_spawn_qrdrone_cylinder_influencer_radius", 1000, reset_dvars ); + ss.qrdrone_cylinder_influencer_length = set_dvar_float_if_unset( "scr_spawn_qrdrone_cylinder_influencer_length", 2000, reset_dvars ); + ss.aitank_influencer_score = set_dvar_float_if_unset( "scr_spawn_aitank_influencer_score", "-200", reset_dvars ); + ss.aitank_influencer_score_curve = set_dvar_if_unset( "scr_spawn_aitank_influencer_score_curve", "linear", reset_dvars ); + ss.aitank_influencer_radius = set_dvar_float_if_unset( "scr_spawn_aitank_influencer_radius", "" + ( 25 * k_player_height ), reset_dvars ); + ss.enemy_spawned_influencer_score_curve = set_dvar_if_unset( "scr_spawn_enemy_spawned_influencer_score_curve", "constant", reset_dvars ); + if ( level.teambased ) + { + ss.enemy_spawned_influencer_score = set_dvar_float_if_unset( "scr_spawn_enemy_spawned_influencer_score", "-200", reset_dvars ); + ss.enemy_spawned_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_spawned_influencer_radius", "" + 1100, reset_dvars ); + } + else + { + ss.enemy_spawned_influencer_score = set_dvar_float_if_unset( "scr_spawn_enemy_spawned_influencer_score", "-100", reset_dvars ); + ss.enemy_spawned_influencer_radius = set_dvar_float_if_unset( "scr_spawn_enemy_spawned_influencer_radius", "" + 400, reset_dvars ); + } + ss.helicopter_influencer_score = set_dvar_float_if_unset( "scr_spawn_helicopter_influencer_score", "-500", reset_dvars ); + ss.helicopter_influencer_score_curve = set_dvar_if_unset( "scr_spawn_helicopter_influencer_score_curve", "linear", reset_dvars ); + ss.helicopter_influencer_radius = set_dvar_float_if_unset( "scr_spawn_helicopter_influencer_radius", "" + 2000, reset_dvars ); + ss.helicopter_influencer_length = set_dvar_float_if_unset( "scr_spawn_helicopter_influencer_length", "" + 3500, reset_dvars ); + ss.tvmissile_influencer_score = set_dvar_float_if_unset( "scr_spawn_tvmissile_influencer_score", "-400", reset_dvars ); + ss.tvmissile_influencer_score_curve = set_dvar_if_unset( "scr_spawn_tvmissile_influencer_score_curve", "linear", reset_dvars ); + ss.tvmissile_influencer_radius = set_dvar_float_if_unset( "scr_spawn_tvmissile_influencer_radius", "" + 2000, reset_dvars ); + ss.tvmissile_influencer_length = set_dvar_float_if_unset( "scr_spawn_tvmissile_influencer_length", "" + 3000, reset_dvars ); + ss.pegasus_influencer_score = set_dvar_float_if_unset( "scr_spawn_pegasus_influencer_score", "-250", reset_dvars ); + ss.pegasus_influencer_score_curve = set_dvar_if_unset( "scr_spawn_pegasus_influencer_score_curve", "linear", reset_dvars ); + ss.pegasus_influencer_radius = set_dvar_float_if_unset( "scr_spawn_pegasus_influencer_radius", "" + ( 20 * k_player_height ), reset_dvars ); + if ( !isDefined( ss.unifiedsideswitching ) ) + { + ss.unifiedsideswitching = 1; + } + set_dvar_int_if_unset( "spawnsystem_allow_non_team_spawns", "0", reset_dvars ); + [[ level.gamemodespawndvars ]]( reset_dvars ); + if ( isDefined( level.levelspawndvars ) ) + { + [[ level.levelspawndvars ]]( reset_dvars ); + } + setspawnpointrandomvariation( ss.randomness_range ); +} + +level_use_unified_spawning( use ) +{ +} + +onspawnplayer_unified( predictedspawn ) +{ + if ( !isDefined( predictedspawn ) ) + { + predictedspawn = 0; + } +/# + if ( getDvarInt( "scr_spawn_point_test_mode" ) != 0 ) + { + spawn_point = get_debug_spawnpoint( self ); + self spawn( spawn_point.origin, spawn_point.angles ); + return; +#/ + } + use_new_spawn_system = 0; + initial_spawn = 1; + if ( isDefined( self.uspawn_already_spawned ) ) + { + initial_spawn = !self.uspawn_already_spawned; + } + if ( level.usestartspawns ) + { + use_new_spawn_system = 0; + } + if ( level.gametype == "sd" ) + { + use_new_spawn_system = 0; + } + set_dvar_if_unset( "scr_spawn_force_unified", "0" ); + [[ level.onspawnplayer ]]( predictedspawn ); + if ( !predictedspawn ) + { + self.uspawn_already_spawned = 1; + } + return; +} + +getspawnpoint( player_entity, predictedspawn ) +{ + if ( !isDefined( predictedspawn ) ) + { + predictedspawn = 0; + } + if ( level.teambased ) + { + point_team = player_entity.pers[ "team" ]; + influencer_team = player_entity.pers[ "team" ]; + } + else + { + point_team = "free"; + influencer_team = "free"; + } + if ( level.teambased && isDefined( game[ "switchedsides" ] ) && game[ "switchedsides" ] && level.spawnsystem.unifiedsideswitching ) + { + point_team = getotherteam( point_team ); + } + best_spawn_entity = get_best_spawnpoint( point_team, influencer_team, player_entity, predictedspawn ); + if ( !predictedspawn ) + { + player_entity.last_spawn_origin = best_spawn_entity.origin; + } + return best_spawn_entity; +} + +get_debug_spawnpoint( player ) +{ + if ( level.teambased ) + { + team = player.pers[ "team" ]; + } + else + { + team = "free"; + } + index = level.test_spawn_point_index; + level.test_spawn_point_index++; + if ( team == "free" ) + { + spawn_counts = 0; + _a1409 = level.teams; + _k1409 = getFirstArrayKey( _a1409 ); + while ( isDefined( _k1409 ) ) + { + team = _a1409[ _k1409 ]; + spawn_counts += level.unified_spawn_points[ team ].a.size; + _k1409 = getNextArrayKey( _a1409, _k1409 ); + } + if ( level.test_spawn_point_index >= spawn_counts ) + { + level.test_spawn_point_index = 0; + } + count = 0; + _a1420 = level.teams; + _k1420 = getFirstArrayKey( _a1420 ); + while ( isDefined( _k1420 ) ) + { + team = _a1420[ _k1420 ]; + size = level.unified_spawn_points[ team ].a.size; + if ( level.test_spawn_point_index < ( count + size ) ) + { + return level.unified_spawn_points[ team ].a[ level.test_spawn_point_index - count ]; + } + count += size; + _k1420 = getNextArrayKey( _a1420, _k1420 ); + } + } + else if ( level.test_spawn_point_index >= level.unified_spawn_points[ team ].a.size ) + { + level.test_spawn_point_index = 0; + } + return level.unified_spawn_points[ team ].a[ level.test_spawn_point_index ]; +} + +get_best_spawnpoint( point_team, influencer_team, player, predictedspawn ) +{ + if ( level.teambased ) + { + vis_team_mask = getotherteamsmask( player.pers[ "team" ] ); + } + else + { + vis_team_mask = level.spawnsystem.ispawn_teammask_free; + } + scored_spawn_points = getsortedspawnpoints( point_team, influencer_team, vis_team_mask, player, predictedspawn ); +/# + assert( scored_spawn_points.size > 0 ); +#/ +/# + assert( scored_spawn_points.size == 1 ); +#/ + if ( !predictedspawn ) + { + bbprint( "mpspawnpointsused", "reason %s x %d y %d z %d", "point used", scored_spawn_points[ 0 ].origin ); + } + return scored_spawn_points[ 0 ]; +} + +gatherspawnentities( player_team ) +{ + if ( !isDefined( level.unified_spawn_points ) ) + { + level.unified_spawn_points = []; + } + else + { + if ( isDefined( level.unified_spawn_points[ player_team ] ) ) + { + return level.unified_spawn_points[ player_team ]; + } + } + spawn_entities_s = spawn_array_struct(); + spawn_entities_s.a = getentarray( "mp_uspawn_point", "classname" ); + if ( !isDefined( spawn_entities_s.a ) ) + { + spawn_entities_s.a = []; + } + legacy_spawn_points = maps/mp/gametypes_zm/_spawnlogic::getteamspawnpoints( player_team ); + legacy_spawn_index = 0; + while ( legacy_spawn_index < legacy_spawn_points.size ) + { + spawn_entities_s.a[ spawn_entities_s.a.size ] = legacy_spawn_points[ legacy_spawn_index ]; + legacy_spawn_index++; + } + level.unified_spawn_points[ player_team ] = spawn_entities_s; + return spawn_entities_s; +} + +is_hardcore() +{ + if ( isDefined( level.hardcoremode ) ) + { + return level.hardcoremode; + } +} + +teams_have_enmity( team1, team2 ) +{ + if ( isDefined( team1 ) || !isDefined( team2 ) && level.gametype == "dm" ) + { + return 1; + } + if ( team1 != "neutral" && team2 != "neutral" ) + { + return team1 != team2; + } +} + +remove_unused_spawn_entities() +{ + spawn_entity_types = []; + spawn_entity_types[ spawn_entity_types.size ] = "mp_dm_spawn"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_allies_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_axis_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_ctf_spawn_allies_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_ctf_spawn_axis_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_ctf_spawn_allies"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_ctf_spawn_axis"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_dom_spawn_allies_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_dom_spawn_axis_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_dom_spawn"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_sab_spawn_allies_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_sab_spawn_axis_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_sab_spawn_allies"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_sab_spawn_axis"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_sd_spawn_attacker"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_sd_spawn_defender"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_twar_spawn_axis_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_twar_spawn_allies_start"; + spawn_entity_types[ spawn_entity_types.size ] = "mp_twar_spawn"; + i = 0; + while ( i < spawn_entity_types.size ) + { + if ( spawn_point_class_name_being_used( spawn_entity_types[ i ] ) ) + { + i++; + continue; + } + else + { + spawnpoints = maps/mp/gametypes_zm/_spawnlogic::getspawnpointarray( spawn_entity_types[ i ] ); + delete_all_spawns( spawnpoints ); + } + i++; + } +} + +delete_all_spawns( spawnpoints ) +{ + i = 0; + while ( i < spawnpoints.size ) + { + spawnpoints[ i ] delete(); + i++; + } +} + +spawn_point_class_name_being_used( name ) +{ + if ( !isDefined( level.spawn_point_class_names ) ) + { + return 0; + } + i = 0; + while ( i < level.spawn_point_class_names.size ) + { + if ( level.spawn_point_class_names[ i ] == name ) + { + return 1; + } + i++; + } + return 0; +} + +codecallback_updatespawnpoints() +{ + _a1624 = level.teams; + _k1624 = getFirstArrayKey( _a1624 ); + while ( isDefined( _k1624 ) ) + { + team = _a1624[ _k1624 ]; + maps/mp/gametypes_zm/_spawnlogic::rebuildspawnpoints( team ); + _k1624 = getNextArrayKey( _a1624, _k1624 ); + } + level.unified_spawn_points = undefined; + updateallspawnpoints(); +} + +initialspawnprotection( specialtyname, spawnmonitorspeed ) +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( !isDefined( level.spawnprotectiontime ) || level.spawnprotectiontime == 0 ) + { + return; + } + if ( specialtyname == "specialty_nottargetedbyairsupport" ) + { + self.specialty_nottargetedbyairsupport = 1; + wait level.spawnprotectiontime; + self.specialty_nottargetedbyairsupport = undefined; + } + else + { + if ( !self hasperk( specialtyname ) ) + { + self setperk( specialtyname ); + wait level.spawnprotectiontime; + self unsetperk( specialtyname ); + } + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_spawnlogic.gsc b/patch_zm/maps/mp/gametypes_zm/_spawnlogic.gsc new file mode 100644 index 0000000..ba21d0f --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_spawnlogic.gsc @@ -0,0 +1,2496 @@ +#include maps/mp/gametypes_zm/_spawnlogic; +#include maps/mp/gametypes_zm/_gameobjects; +#include maps/mp/gametypes_zm/_callbacksetup; +#include maps/mp/_utility; +#include common_scripts/utility; + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + } +} + +findboxcenter( mins, maxs ) +{ + center = ( -1, -1, -1 ); + center = maxs - mins; + center = ( center[ 0 ] / 2, center[ 1 ] / 2, center[ 2 ] / 2 ) + mins; + return center; +} + +expandmins( mins, point ) +{ + if ( mins[ 0 ] > point[ 0 ] ) + { + mins = ( point[ 0 ], mins[ 1 ], mins[ 2 ] ); + } + if ( mins[ 1 ] > point[ 1 ] ) + { + mins = ( mins[ 0 ], point[ 1 ], mins[ 2 ] ); + } + if ( mins[ 2 ] > point[ 2 ] ) + { + mins = ( mins[ 0 ], mins[ 1 ], point[ 2 ] ); + } + return mins; +} + +expandmaxs( maxs, point ) +{ + if ( maxs[ 0 ] < point[ 0 ] ) + { + maxs = ( point[ 0 ], maxs[ 1 ], maxs[ 2 ] ); + } + if ( maxs[ 1 ] < point[ 1 ] ) + { + maxs = ( maxs[ 0 ], point[ 1 ], maxs[ 2 ] ); + } + if ( maxs[ 2 ] < point[ 2 ] ) + { + maxs = ( maxs[ 0 ], maxs[ 1 ], point[ 2 ] ); + } + return maxs; +} + +addspawnpointsinternal( team, spawnpointname ) +{ + oldspawnpoints = []; + if ( level.teamspawnpoints[ team ].size ) + { + oldspawnpoints = level.teamspawnpoints[ team ]; + } + level.teamspawnpoints[ team ] = getspawnpointarray( spawnpointname ); + if ( !isDefined( level.spawnpoints ) ) + { + level.spawnpoints = []; + } + index = 0; + while ( index < level.teamspawnpoints[ team ].size ) + { + spawnpoint = level.teamspawnpoints[ team ][ index ]; + if ( !isDefined( spawnpoint.inited ) ) + { + spawnpoint spawnpointinit(); + level.spawnpoints[ level.spawnpoints.size ] = spawnpoint; + } + index++; + } + index = 0; + while ( index < oldspawnpoints.size ) + { + origin = oldspawnpoints[ index ].origin; + level.spawnmins = expandmins( level.spawnmins, origin ); + level.spawnmaxs = expandmaxs( level.spawnmaxs, origin ); + level.teamspawnpoints[ team ][ level.teamspawnpoints[ team ].size ] = oldspawnpoints[ index ]; + index++; + } + if ( !level.teamspawnpoints[ team ].size ) + { +/# + println( "^1ERROR: No " + spawnpointname + " spawnpoints found in level!" ); +#/ + maps/mp/gametypes_zm/_callbacksetup::abortlevel(); + wait 1; + return; + } +} + +clearspawnpoints() +{ + _a87 = level.teams; + _k87 = getFirstArrayKey( _a87 ); + while ( isDefined( _k87 ) ) + { + team = _a87[ _k87 ]; + level.teamspawnpoints[ team ] = []; + _k87 = getNextArrayKey( _a87, _k87 ); + } + level.spawnpoints = []; + level.unified_spawn_points = undefined; +} + +addspawnpoints( team, spawnpointname ) +{ + addspawnpointclassname( spawnpointname ); + addspawnpointteamclassname( team, spawnpointname ); + addspawnpointsinternal( team, spawnpointname ); +} + +rebuildspawnpoints( team ) +{ + level.teamspawnpoints[ team ] = []; + index = 0; + while ( index < level.spawn_point_team_class_names[ team ].size ) + { + addspawnpointsinternal( team, level.spawn_point_team_class_names[ team ][ index ] ); + index++; + } +} + +placespawnpoints( spawnpointname ) +{ + addspawnpointclassname( spawnpointname ); + spawnpoints = getspawnpointarray( spawnpointname ); +/# + if ( !isDefined( level.extraspawnpointsused ) ) + { + level.extraspawnpointsused = []; +#/ + } + if ( !spawnpoints.size ) + { +/# + println( "^1No " + spawnpointname + " spawnpoints found in level!" ); +#/ + maps/mp/gametypes_zm/_callbacksetup::abortlevel(); + wait 1; + return; + } + index = 0; + while ( index < spawnpoints.size ) + { + spawnpoints[ index ] spawnpointinit(); +/# + spawnpoints[ index ].fakeclassname = spawnpointname; + level.extraspawnpointsused[ level.extraspawnpointsused.size ] = spawnpoints[ index ]; +#/ + index++; + } +} + +dropspawnpoints( spawnpointname ) +{ + spawnpoints = getspawnpointarray( spawnpointname ); + if ( !spawnpoints.size ) + { +/# + println( "^1No " + spawnpointname + " spawnpoints found in level!" ); +#/ + return; + } + index = 0; + while ( index < spawnpoints.size ) + { + spawnpoints[ index ] placespawnpoint(); + index++; + } +} + +addspawnpointclassname( spawnpointclassname ) +{ + if ( !isDefined( level.spawn_point_class_names ) ) + { + level.spawn_point_class_names = []; + } + level.spawn_point_class_names[ level.spawn_point_class_names.size ] = spawnpointclassname; +} + +addspawnpointteamclassname( team, spawnpointclassname ) +{ + level.spawn_point_team_class_names[ team ][ level.spawn_point_team_class_names[ team ].size ] = spawnpointclassname; +} + +getspawnpointarray( classname ) +{ + spawnpoints = getentarray( classname, "classname" ); + if ( !isDefined( level.extraspawnpoints ) || !isDefined( level.extraspawnpoints[ classname ] ) ) + { + return spawnpoints; + } + i = 0; + while ( i < level.extraspawnpoints[ classname ].size ) + { + spawnpoints[ spawnpoints.size ] = level.extraspawnpoints[ classname ][ i ]; + i++; + } + return spawnpoints; +} + +spawnpointinit() +{ + spawnpoint = self; + origin = spawnpoint.origin; + if ( !level.spawnminsmaxsprimed ) + { + level.spawnmins = origin; + level.spawnmaxs = origin; + level.spawnminsmaxsprimed = 1; + } + else + { + level.spawnmins = expandmins( level.spawnmins, origin ); + level.spawnmaxs = expandmaxs( level.spawnmaxs, origin ); + } + spawnpoint placespawnpoint(); + spawnpoint.forward = anglesToForward( spawnpoint.angles ); + spawnpoint.sighttracepoint = spawnpoint.origin + vectorScale( ( -1, -1, -1 ), 50 ); + spawnpoint.inited = 1; +} + +getteamspawnpoints( team ) +{ + return level.teamspawnpoints[ team ]; +} + +getspawnpoint_final( spawnpoints, useweights ) +{ + bestspawnpoint = undefined; + if ( !isDefined( spawnpoints ) || spawnpoints.size == 0 ) + { + return undefined; + } + if ( !isDefined( useweights ) ) + { + useweights = 1; + } + if ( useweights ) + { + bestspawnpoint = getbestweightedspawnpoint( spawnpoints ); + thread spawnweightdebug( spawnpoints ); + } + else i = 0; + while ( i < spawnpoints.size ) + { + if ( isDefined( self.lastspawnpoint ) && self.lastspawnpoint == spawnpoints[ i ] ) + { + i++; + continue; + } + else + { + if ( positionwouldtelefrag( spawnpoints[ i ].origin ) ) + { + i++; + continue; + } + else + { + bestspawnpoint = spawnpoints[ i ]; + break; + } + } + i++; + } + while ( !isDefined( bestspawnpoint ) ) + { + while ( isDefined( self.lastspawnpoint ) && !positionwouldtelefrag( self.lastspawnpoint.origin ) ) + { + i = 0; + while ( i < spawnpoints.size ) + { + if ( spawnpoints[ i ] == self.lastspawnpoint ) + { + bestspawnpoint = spawnpoints[ i ]; + break; + } + else + { + i++; + } + } + } + } + if ( !isDefined( bestspawnpoint ) ) + { + if ( useweights ) + { + bestspawnpoint = spawnpoints[ randomint( spawnpoints.size ) ]; + } + else + { + bestspawnpoint = spawnpoints[ 0 ]; + } + } + self finalizespawnpointchoice( bestspawnpoint ); +/# + self storespawndata( spawnpoints, useweights, bestspawnpoint ); +#/ + return bestspawnpoint; +} + +finalizespawnpointchoice( spawnpoint ) +{ + time = getTime(); + self.lastspawnpoint = spawnpoint; + self.lastspawntime = time; + spawnpoint.lastspawnedplayer = self; + spawnpoint.lastspawntime = time; +} + +getbestweightedspawnpoint( spawnpoints ) +{ + maxsighttracedspawnpoints = 3; + try = 0; + while ( try <= maxsighttracedspawnpoints ) + { + bestspawnpoints = []; + bestweight = undefined; + bestspawnpoint = undefined; + i = 0; + while ( i < spawnpoints.size ) + { + if ( !isDefined( bestweight ) || spawnpoints[ i ].weight > bestweight ) + { + if ( positionwouldtelefrag( spawnpoints[ i ].origin ) ) + { + i++; + continue; + } + else bestspawnpoints = []; + bestspawnpoints[ 0 ] = spawnpoints[ i ]; + bestweight = spawnpoints[ i ].weight; + i++; + continue; + } + else + { + if ( spawnpoints[ i ].weight == bestweight ) + { + if ( positionwouldtelefrag( spawnpoints[ i ].origin ) ) + { + i++; + continue; + } + else + { + bestspawnpoints[ bestspawnpoints.size ] = spawnpoints[ i ]; + } + } + } + i++; + } + if ( bestspawnpoints.size == 0 ) + { + return undefined; + } + bestspawnpoint = bestspawnpoints[ randomint( bestspawnpoints.size ) ]; + if ( try == maxsighttracedspawnpoints ) + { + return bestspawnpoint; + } + if ( isDefined( bestspawnpoint.lastsighttracetime ) && bestspawnpoint.lastsighttracetime == getTime() ) + { + return bestspawnpoint; + } + if ( !lastminutesighttraces( bestspawnpoint ) ) + { + return bestspawnpoint; + } + penalty = getlospenalty(); +/# + if ( level.storespawndata || level.debugspawning ) + { + bestspawnpoint.spawndata[ bestspawnpoint.spawndata.size ] = "Last minute sight trace: -" + penalty; +#/ + } + bestspawnpoint.weight -= penalty; + bestspawnpoint.lastsighttracetime = getTime(); + try++; + } +} + +checkbad( spawnpoint ) +{ +/# + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( !isalive( player ) || player.sessionstate != "playing" ) + { + i++; + continue; + } + else + { + if ( level.teambased && player.team == self.team ) + { + i++; + continue; + } + else + { + losexists = bullettracepassed( player.origin + vectorScale( ( -1, -1, -1 ), 50 ), spawnpoint.sighttracepoint, 0, undefined ); + if ( losexists ) + { + thread badspawnline( spawnpoint.sighttracepoint, player.origin + vectorScale( ( -1, -1, -1 ), 50 ), self.name, player.name ); + } + } + } + i++; +#/ + } +} + +badspawnline( start, end, name1, name2 ) +{ +/# + dist = distance( start, end ); + i = 0; + while ( i < 200 ) + { + line( start, end, ( -1, -1, -1 ) ); + print3d( start, "Bad spawn! " + name1 + ", dist = " + dist ); + print3d( end, name2 ); + wait 0,05; + i++; +#/ + } +} + +storespawndata( spawnpoints, useweights, bestspawnpoint ) +{ +/# + if ( !isDefined( level.storespawndata ) || !level.storespawndata ) + { + return; + } + level.storespawndata = getDvarInt( "scr_recordspawndata" ); + if ( !level.storespawndata ) + { + return; + } + if ( !isDefined( level.spawnid ) ) + { + level.spawngameid = randomint( 100 ); + level.spawnid = 0; + } + if ( bestspawnpoint.classname == "mp_global_intermission" ) + { + return; + } + level.spawnid++; + file = openfile( "spawndata.txt", "append" ); + fprintfields( file, ( level.spawngameid + "." ) + level.spawnid + "," + spawnpoints.size + "," + self.name ); + i = 0; + while ( i < spawnpoints.size ) + { + str = vectostr( spawnpoints[ i ].origin ) + ","; + if ( spawnpoints[ i ] == bestspawnpoint ) + { + str += "1,"; + } + else + { + str += "0,"; + } + if ( !useweights ) + { + str += "0,"; + } + else + { + str += spawnpoints[ i ].weight + ","; + } + if ( !isDefined( spawnpoints[ i ].spawndata ) ) + { + spawnpoints[ i ].spawndata = []; + } + if ( !isDefined( spawnpoints[ i ].sightchecks ) ) + { + spawnpoints[ i ].sightchecks = []; + } + str += spawnpoints[ i ].spawndata.size + ","; + j = 0; + while ( j < spawnpoints[ i ].spawndata.size ) + { + str += spawnpoints[ i ].spawndata[ j ] + ","; + j++; + } + str += spawnpoints[ i ].sightchecks.size + ","; + j = 0; + while ( j < spawnpoints[ i ].sightchecks.size ) + { + str += ( spawnpoints[ i ].sightchecks[ j ].penalty + "," ) + vectostr( spawnpoints[ i ].origin ) + ","; + j++; + } + fprintfields( file, str ); + i++; + } + obj = spawnstruct(); + getallalliedandenemyplayers( obj ); + numallies = 0; + numenemies = 0; + str = ""; + i = 0; + while ( i < obj.allies.size ) + { + if ( obj.allies[ i ] == self ) + { + i++; + continue; + } + else + { + numallies++; + str += vectostr( obj.allies[ i ].origin ) + ","; + } + i++; + } + i = 0; + while ( i < obj.enemies.size ) + { + numenemies++; + str += vectostr( obj.enemies[ i ].origin ) + ","; + i++; + } + str = ( numallies + "," ) + numenemies + "," + str; + fprintfields( file, str ); + otherdata = []; + if ( isDefined( level.bombguy ) ) + { + index = otherdata.size; + otherdata[ index ] = spawnstruct(); + otherdata[ index ].origin = level.bombguy.origin + vectorScale( ( -1, -1, -1 ), 20 ); + otherdata[ index ].text = "Bomb holder"; + } + else + { + if ( isDefined( level.bombpos ) ) + { + index = otherdata.size; + otherdata[ index ] = spawnstruct(); + otherdata[ index ].origin = level.bombpos; + otherdata[ index ].text = "Bomb"; + } + } + while ( isDefined( level.flags ) ) + { + i = 0; + while ( i < level.flags.size ) + { + index = otherdata.size; + otherdata[ index ] = spawnstruct(); + otherdata[ index ].origin = level.flags[ i ].origin; + otherdata[ index ].text = level.flags[ i ].useobj maps/mp/gametypes_zm/_gameobjects::getownerteam() + " flag"; + i++; + } + } + str = otherdata.size + ","; + i = 0; + while ( i < otherdata.size ) + { + str += vectostr( otherdata[ i ].origin ) + "," + otherdata[ i ].text + ","; + i++; + } + fprintfields( file, str ); + closefile( file ); + thisspawnid = ( level.spawngameid + "." ) + level.spawnid; + if ( isDefined( self.thisspawnid ) ) + { + } + self.thisspawnid = thisspawnid; +#/ +} + +readspawndata( desiredid, relativepos ) +{ +/# + file = openfile( "spawndata.txt", "read" ); + if ( file < 0 ) + { + return; + } + oldspawndata = level.curspawndata; + level.curspawndata = undefined; + prev = undefined; + prevthisplayer = undefined; + lookingfornextthisplayer = 0; + lookingfornext = 0; + if ( isDefined( relativepos ) && !isDefined( oldspawndata ) ) + { + return; + } + while ( 1 ) + { + if ( freadln( file ) <= 0 ) + { + break; + } + else data = spawnstruct(); + data.id = fgetarg( file, 0 ); + numspawns = int( fgetarg( file, 1 ) ); + if ( numspawns > 256 ) + { + break; + } + else data.playername = fgetarg( file, 2 ); + data.spawnpoints = []; + data.friends = []; + data.enemies = []; + data.otherdata = []; + i = 0; + while ( i < numspawns ) + { + if ( freadln( file ) <= 0 ) + { + break; + } + else spawnpoint = spawnstruct(); + spawnpoint.origin = strtovec( fgetarg( file, 0 ) ); + spawnpoint.winner = int( fgetarg( file, 1 ) ); + spawnpoint.weight = int( fgetarg( file, 2 ) ); + spawnpoint.data = []; + spawnpoint.sightchecks = []; + if ( i == 0 ) + { + data.minweight = spawnpoint.weight; + data.maxweight = spawnpoint.weight; + } + else + { + if ( spawnpoint.weight < data.minweight ) + { + data.minweight = spawnpoint.weight; + } + if ( spawnpoint.weight > data.maxweight ) + { + data.maxweight = spawnpoint.weight; + } + } + argnum = 4; + numdata = int( fgetarg( file, 3 ) ); + if ( numdata > 256 ) + { + break; + } + else j = 0; + while ( j < numdata ) + { + spawnpoint.data[ spawnpoint.data.size ] = fgetarg( file, argnum ); + argnum++; + j++; + } + numsightchecks = int( fgetarg( file, argnum ) ); + argnum++; + if ( numsightchecks > 256 ) + { + break; + } + else + { + j = 0; + while ( j < numsightchecks ) + { + index = spawnpoint.sightchecks.size; + spawnpoint.sightchecks[ index ] = spawnstruct(); + spawnpoint.sightchecks[ index ].penalty = int( fgetarg( file, argnum ) ); + argnum++; + spawnpoint.sightchecks[ index ].origin = strtovec( fgetarg( file, argnum ) ); + argnum++; + j++; + } + data.spawnpoints[ data.spawnpoints.size ] = spawnpoint; + i++; + } + } + if ( !isDefined( data.minweight ) ) + { + data.minweight = -1; + data.maxweight = 0; + } + if ( data.minweight == data.maxweight ) + { + data.minweight -= 1; + } + if ( freadln( file ) <= 0 ) + { + break; + } + else numfriends = int( fgetarg( file, 0 ) ); + numenemies = int( fgetarg( file, 1 ) ); + if ( numfriends > 32 || numenemies > 32 ) + { + break; + } + else + { + argnum = 2; + i = 0; + while ( i < numfriends ) + { + data.friends[ data.friends.size ] = strtovec( fgetarg( file, argnum ) ); + argnum++; + i++; + } + i = 0; + while ( i < numenemies ) + { + data.enemies[ data.enemies.size ] = strtovec( fgetarg( file, argnum ) ); + argnum++; + i++; + } + if ( freadln( file ) <= 0 ) + { + break; + } + else numotherdata = int( fgetarg( file, 0 ) ); + argnum = 1; + i = 0; + while ( i < numotherdata ) + { + otherdata = spawnstruct(); + otherdata.origin = strtovec( fgetarg( file, argnum ) ); + argnum++; + otherdata.text = fgetarg( file, argnum ); + argnum++; + data.otherdata[ data.otherdata.size ] = otherdata; + i++; + } + if ( isDefined( relativepos ) ) + { + if ( relativepos == "prevthisplayer" ) + { + if ( data.id == oldspawndata.id ) + { + level.curspawndata = prevthisplayer; + break; + } + else } + else if ( relativepos == "prev" ) + { + if ( data.id == oldspawndata.id ) + { + level.curspawndata = prev; + break; + } + else } + else if ( relativepos == "nextthisplayer" ) + { + if ( lookingfornextthisplayer ) + { + level.curspawndata = data; + break; + } + else if ( data.id == oldspawndata.id ) + { + lookingfornextthisplayer = 1; + } + } + else if ( relativepos == "next" ) + { + if ( lookingfornext ) + { + level.curspawndata = data; + break; + } + else if ( data.id == oldspawndata.id ) + { + lookingfornext = 1; + } + } + } + else + { + if ( data.id == desiredid ) + { + level.curspawndata = data; + break; + } + } + else + { + prev = data; + if ( isDefined( oldspawndata ) && data.playername == oldspawndata.playername ) + { + prevthisplayer = data; + } + } + } + } + closefile( file ); +#/ +} + +drawspawndata() +{ +/# + level notify( "drawing_spawn_data" ); + level endon( "drawing_spawn_data" ); + textoffset = vectorScale( ( -1, -1, -1 ), 12 ); + while ( 1 ) + { + while ( !isDefined( level.curspawndata ) ) + { + wait 0,5; + } + i = 0; + while ( i < level.curspawndata.friends.size ) + { + print3d( level.curspawndata.friends[ i ], "=)", ( 0,5, 1, 0,5 ), 1, 5 ); + i++; + } + i = 0; + while ( i < level.curspawndata.enemies.size ) + { + print3d( level.curspawndata.enemies[ i ], "=(", ( 1, 0,5, 0,5 ), 1, 5 ); + i++; + } + i = 0; + while ( i < level.curspawndata.otherdata.size ) + { + print3d( level.curspawndata.otherdata[ i ].origin, level.curspawndata.otherdata[ i ].text, ( 0,5, 0,75, 1 ), 1, 2 ); + i++; + } + i = 0; + while ( i < level.curspawndata.spawnpoints.size ) + { + sp = level.curspawndata.spawnpoints[ i ]; + orig = sp.sighttracepoint; + if ( sp.winner ) + { + print3d( orig, level.curspawndata.playername + " spawned here", ( 0,5, 0,5, 1 ), 1, 2 ); + orig += textoffset; + } + amnt = ( sp.weight - level.curspawndata.minweight ) / ( level.curspawndata.maxweight - level.curspawndata.minweight ); + print3d( orig, "Weight: " + sp.weight, ( 1 - amnt, amnt, 0,5 ) ); + orig += textoffset; + j = 0; + while ( j < sp.data.size ) + { + print3d( orig, sp.data[ j ], ( -1, -1, -1 ) ); + orig += textoffset; + j++; + } + j = 0; + while ( j < sp.sightchecks.size ) + { + print3d( orig, "Sightchecks: -" + sp.sightchecks[ j ].penalty, ( 1, 0,5, 0,5 ) ); + orig += textoffset; + j++; + } + i++; + } + wait 0,05; +#/ + } +} + +vectostr( vec ) +{ +/# + return int( vec[ 0 ] ) + "/" + int( vec[ 1 ] ) + "/" + int( vec[ 2 ] ); +#/ +} + +strtovec( str ) +{ +/# + parts = strtok( str, "/" ); + if ( parts.size != 3 ) + { + return ( -1, -1, -1 ); + } + return ( int( parts[ 0 ] ), int( parts[ 1 ] ), int( parts[ 2 ] ) ); +#/ +} + +getspawnpoint_random( spawnpoints ) +{ + if ( !isDefined( spawnpoints ) ) + { + return undefined; + } + i = 0; + while ( i < spawnpoints.size ) + { + j = randomint( spawnpoints.size ); + spawnpoint = spawnpoints[ i ]; + spawnpoints[ i ] = spawnpoints[ j ]; + spawnpoints[ j ] = spawnpoint; + i++; + } + return getspawnpoint_final( spawnpoints, 0 ); +} + +getallotherplayers() +{ + aliveplayers = []; + i = 0; + while ( i < level.players.size ) + { + if ( !isDefined( level.players[ i ] ) ) + { + i++; + continue; + } + else player = level.players[ i ]; + if ( player.sessionstate != "playing" || player == self ) + { + i++; + continue; + } + else + { + if ( isDefined( level.customalivecheck ) ) + { + if ( !( [[ level.customalivecheck ]]( player ) ) ) + { + i++; + continue; + } + } + else + { + aliveplayers[ aliveplayers.size ] = player; + } + } + i++; + } + return aliveplayers; +} + +getallalliedandenemyplayers( obj ) +{ + if ( level.teambased ) + { +/# + assert( isDefined( level.teams[ self.team ] ) ); +#/ + obj.allies = []; + obj.enemies = []; + i = 0; + while ( i < level.players.size ) + { + if ( !isDefined( level.players[ i ] ) ) + { + i++; + continue; + } + else player = level.players[ i ]; + if ( player.sessionstate != "playing" || player == self ) + { + i++; + continue; + } + else + { + if ( isDefined( level.customalivecheck ) ) + { + if ( !( [[ level.customalivecheck ]]( player ) ) ) + { + i++; + continue; + } + } + else if ( player.team == self.team ) + { + obj.allies[ obj.allies.size ] = player; + i++; + continue; + } + else + { + obj.enemies[ obj.enemies.size ] = player; + } + } + i++; + } + } + else obj.allies = []; + obj.enemies = level.activeplayers; +} + +initweights( spawnpoints ) +{ + i = 0; + while ( i < spawnpoints.size ) + { + spawnpoints[ i ].weight = 0; + i++; + } +/# + while ( level.storespawndata || level.debugspawning ) + { + i = 0; + while ( i < spawnpoints.size ) + { + spawnpoints[ i ].spawndata = []; + spawnpoints[ i ].sightchecks = []; + i++; +#/ + } + } +} + +spawnpointupdate_zm( spawnpoint ) +{ + _a906 = level.teams; + _k906 = getFirstArrayKey( _a906 ); + while ( isDefined( _k906 ) ) + { + team = _a906[ _k906 ]; + spawnpoint.distsum[ team ] = 0; + spawnpoint.enemydistsum[ team ] = 0; + _k906 = getNextArrayKey( _a906, _k906 ); + } + players = get_players(); + spawnpoint.numplayersatlastupdate = players.size; + _a913 = players; + _k913 = getFirstArrayKey( _a913 ); + while ( isDefined( _k913 ) ) + { + player = _a913[ _k913 ]; + if ( !isDefined( player ) ) + { + } + else if ( player.sessionstate != "playing" ) + { + } + else if ( isDefined( level.customalivecheck ) ) + { + if ( !( [[ level.customalivecheck ]]( player ) ) ) + { + } + } + else + { + dist = distance( spawnpoint.origin, player.origin ); + spawnpoint.distsum[ player.team ] += dist; + _a924 = level.teams; + _k924 = getFirstArrayKey( _a924 ); + while ( isDefined( _k924 ) ) + { + team = _a924[ _k924 ]; + if ( team != player.team ) + { + spawnpoint.enemydistsum[ team ] += dist; + } + _k924 = getNextArrayKey( _a924, _k924 ); + } + } + _k913 = getNextArrayKey( _a913, _k913 ); + } +} + +getspawnpoint_nearteam( spawnpoints, favoredspawnpoints, forceallydistanceweight, forceenemydistanceweight ) +{ + if ( !isDefined( spawnpoints ) ) + { + return undefined; + } +/# + if ( getDvar( "scr_spawn_randomly" ) == "" ) + { + setdvar( "scr_spawn_randomly", "0" ); + } + if ( getDvar( "scr_spawn_randomly" ) == "1" ) + { + return getspawnpoint_random( spawnpoints ); +#/ + } + if ( getDvarInt( "scr_spawnsimple" ) > 0 ) + { + return getspawnpoint_random( spawnpoints ); + } + spawnlogic_begin(); + k_favored_spawn_point_bonus = 25000; + initweights( spawnpoints ); + obj = spawnstruct(); + getallalliedandenemyplayers( obj ); + numplayers = obj.allies.size + obj.enemies.size; + allieddistanceweight = 2; + if ( isDefined( forceallydistanceweight ) ) + { + allieddistanceweight = forceallydistanceweight; + } + enemydistanceweight = 1; + if ( isDefined( forceenemydistanceweight ) ) + { + enemydistanceweight = forceenemydistanceweight; + } + myteam = self.team; + i = 0; + while ( i < spawnpoints.size ) + { + spawnpoint = spawnpoints[ i ]; + spawnpointupdate_zm( spawnpoint ); + if ( !isDefined( spawnpoint.numplayersatlastupdate ) ) + { + spawnpoint.numplayersatlastupdate = 0; + } + if ( spawnpoint.numplayersatlastupdate > 0 ) + { + allydistsum = spawnpoint.distsum[ myteam ]; + enemydistsum = spawnpoint.enemydistsum[ myteam ]; + spawnpoint.weight = ( ( enemydistanceweight * enemydistsum ) - ( allieddistanceweight * allydistsum ) ) / spawnpoint.numplayersatlastupdate; +/# + if ( level.storespawndata || level.debugspawning ) + { + spawnpoint.spawndata[ spawnpoint.spawndata.size ] = "Base weight: " + int( spawnpoint.weight ) + " = (" + enemydistanceweight + "*" + int( enemydistsum ) + " - " + allieddistanceweight + "*" + int( allydistsum ) + ") / " + spawnpoint.numplayersatlastupdate; +#/ + } + i++; + continue; + } + else + { + spawnpoint.weight = 0; +/# + if ( level.storespawndata || level.debugspawning ) + { + spawnpoint.spawndata[ spawnpoint.spawndata.size ] = "Base weight: 0"; +#/ + } + } + i++; + } + while ( isDefined( favoredspawnpoints ) ) + { + i = 0; + while ( i < favoredspawnpoints.size ) + { + if ( isDefined( favoredspawnpoints[ i ].weight ) ) + { + favoredspawnpoints[ i ].weight += k_favored_spawn_point_bonus; + i++; + continue; + } + else + { + favoredspawnpoints[ i ].weight = k_favored_spawn_point_bonus; + } + i++; + } + } + avoidsamespawn( spawnpoints ); + avoidspawnreuse( spawnpoints, 1 ); + avoidweapondamage( spawnpoints ); + avoidvisibleenemies( spawnpoints, 1 ); + result = getspawnpoint_final( spawnpoints ); +/# + if ( getDvar( "scr_spawn_showbad" ) == "" ) + { + setdvar( "scr_spawn_showbad", "0" ); + } + if ( getDvar( "scr_spawn_showbad" ) == "1" ) + { + checkbad( result ); +#/ + } + return result; +} + +getspawnpoint_dm( spawnpoints ) +{ + if ( !isDefined( spawnpoints ) ) + { + return undefined; + } + spawnlogic_begin(); + initweights( spawnpoints ); + aliveplayers = getallotherplayers(); + idealdist = 1600; + baddist = 1200; + while ( aliveplayers.size > 0 ) + { + i = 0; + while ( i < spawnpoints.size ) + { + totaldistfromideal = 0; + nearbybadamount = 0; + j = 0; + while ( j < aliveplayers.size ) + { + dist = distance( spawnpoints[ i ].origin, aliveplayers[ j ].origin ); + if ( dist < baddist ) + { + nearbybadamount += ( baddist - dist ) / baddist; + } + distfromideal = abs( dist - idealdist ); + totaldistfromideal += distfromideal; + j++; + } + avgdistfromideal = totaldistfromideal / aliveplayers.size; + welldistancedamount = ( idealdist - avgdistfromideal ) / idealdist; + spawnpoints[ i ].weight = ( welldistancedamount - ( nearbybadamount * 2 ) ) + randomfloat( 0,2 ); + i++; + } + } + avoidsamespawn( spawnpoints ); + avoidspawnreuse( spawnpoints, 0 ); + avoidweapondamage( spawnpoints ); + avoidvisibleenemies( spawnpoints, 0 ); + return getspawnpoint_final( spawnpoints ); +} + +getspawnpoint_turned( spawnpoints, idealdist, baddist, idealdistteam, baddistteam ) +{ + if ( !isDefined( spawnpoints ) ) + { + return undefined; + } + spawnlogic_begin(); + initweights( spawnpoints ); + aliveplayers = getallotherplayers(); + if ( !isDefined( idealdist ) ) + { + idealdist = 1600; + } + if ( !isDefined( idealdistteam ) ) + { + idealdistteam = 1200; + } + if ( !isDefined( baddist ) ) + { + baddist = 1200; + } + if ( !isDefined( baddistteam ) ) + { + baddistteam = 600; + } + myteam = self.team; + while ( aliveplayers.size > 0 ) + { + i = 0; + while ( i < spawnpoints.size ) + { + totaldistfromideal = 0; + nearbybadamount = 0; + j = 0; + while ( j < aliveplayers.size ) + { + dist = distance( spawnpoints[ i ].origin, aliveplayers[ j ].origin ); + distfromideal = 0; + if ( aliveplayers[ j ].team == myteam ) + { + if ( dist < baddistteam ) + { + nearbybadamount += ( baddistteam - dist ) / baddistteam; + } + distfromideal = abs( dist - idealdistteam ); + } + else + { + if ( dist < baddist ) + { + nearbybadamount += ( baddist - dist ) / baddist; + } + distfromideal = abs( dist - idealdist ); + } + totaldistfromideal += distfromideal; + j++; + } + avgdistfromideal = totaldistfromideal / aliveplayers.size; + welldistancedamount = ( idealdist - avgdistfromideal ) / idealdist; + spawnpoints[ i ].weight = ( welldistancedamount - ( nearbybadamount * 2 ) ) + randomfloat( 0,2 ); + i++; + } + } + avoidsamespawn( spawnpoints ); + avoidspawnreuse( spawnpoints, 0 ); + avoidweapondamage( spawnpoints ); + avoidvisibleenemies( spawnpoints, 0 ); + return getspawnpoint_final( spawnpoints ); +} + +spawnlogic_begin() +{ +/# + level.storespawndata = getDvarInt( "scr_recordspawndata" ); + level.debugspawning = getDvarInt( "scr_spawnpointdebug" ) > 0; +#/ +} + +init() +{ +/# + if ( getDvar( "scr_recordspawndata" ) == "" ) + { + setdvar( "scr_recordspawndata", 0 ); + } + level.storespawndata = getDvarInt( "scr_recordspawndata" ); + if ( getDvar( "scr_killbots" ) == "" ) + { + setdvar( "scr_killbots", 0 ); + } + if ( getDvar( "scr_killbottimer" ) == "" ) + { + setdvar( "scr_killbottimer", 0,25 ); + } + thread loopbotspawns(); +#/ + level.spawnlogic_deaths = []; + level.spawnlogic_spawnkills = []; + level.players = []; + level.grenades = []; + level.pipebombs = []; + level.spawnmins = ( -1, -1, -1 ); + level.spawnmaxs = ( -1, -1, -1 ); + level.spawnminsmaxsprimed = 0; + while ( isDefined( level.safespawns ) ) + { + i = 0; + while ( i < level.safespawns.size ) + { + level.safespawns[ i ] spawnpointinit(); + i++; + } + } + if ( getDvar( "scr_spawn_enemyavoiddist" ) == "" ) + { + setdvar( "scr_spawn_enemyavoiddist", "800" ); + } + if ( getDvar( "scr_spawn_enemyavoidweight" ) == "" ) + { + setdvar( "scr_spawn_enemyavoidweight", "0" ); + } +/# + if ( getDvar( "scr_spawnsimple" ) == "" ) + { + setdvar( "scr_spawnsimple", "0" ); + } + if ( getDvar( "scr_spawnpointdebug" ) == "" ) + { + setdvar( "scr_spawnpointdebug", "0" ); + } + if ( getDvarInt( "scr_spawnpointdebug" ) > 0 ) + { + thread showdeathsdebug(); + thread updatedeathinfodebug(); + thread profiledebug(); + } + if ( level.storespawndata ) + { + thread allowspawndatareading(); + } + if ( getDvar( "scr_spawnprofile" ) == "" ) + { + setdvar( "scr_spawnprofile", "0" ); + } + thread watchspawnprofile(); + thread spawngraphcheck(); +#/ +} + +watchspawnprofile() +{ +/# + while ( 1 ) + { + while ( 1 ) + { + if ( getDvarInt( "scr_spawnprofile" ) > 0 ) + { + break; + } + else + { + wait 0,05; + } + } + thread spawnprofile(); + while ( 1 ) + { + if ( getDvarInt( "scr_spawnprofile" ) <= 0 ) + { + break; + } + else + { + wait 0,05; + } + } + level notify( "stop_spawn_profile" ); +#/ + } +} + +spawnprofile() +{ +/# + level endon( "stop_spawn_profile" ); + while ( 1 ) + { + if ( level.players.size > 0 && level.spawnpoints.size > 0 ) + { + playernum = randomint( level.players.size ); + player = level.players[ playernum ]; + attempt = 1; + while ( !isDefined( player ) && attempt < level.players.size ) + { + playernum = ( playernum + 1 ) % level.players.size; + attempt++; + player = level.players[ playernum ]; + } + player getspawnpoint_nearteam( level.spawnpoints ); + } + wait 0,05; +#/ + } +} + +spawngraphcheck() +{ +/# + while ( 1 ) + { + while ( getDvarInt( #"C25B6B47" ) < 1 ) + { + wait 3; + } + thread spawngraph(); + return; +#/ + } +} + +spawngraph() +{ +/# + w = 20; + h = 20; + weightscale = 0,1; + fakespawnpoints = []; + corners = getentarray( "minimap_corner", "targetname" ); + if ( corners.size != 2 ) + { + println( "^1 can't spawn graph: no minimap corners" ); + return; + } + min = corners[ 0 ].origin; + max = corners[ 0 ].origin; + if ( corners[ 1 ].origin[ 0 ] > max[ 0 ] ) + { + max = ( corners[ 1 ].origin[ 0 ], max[ 1 ], max[ 2 ] ); + } + else + { + min = ( corners[ 1 ].origin[ 0 ], min[ 1 ], min[ 2 ] ); + } + if ( corners[ 1 ].origin[ 1 ] > max[ 1 ] ) + { + max = ( max[ 0 ], corners[ 1 ].origin[ 1 ], max[ 2 ] ); + } + else + { + min = ( min[ 0 ], corners[ 1 ].origin[ 1 ], min[ 2 ] ); + } + i = 0; + y = 0; + while ( y < h ) + { + yamnt = y / ( h - 1 ); + x = 0; + while ( x < w ) + { + xamnt = x / ( w - 1 ); + fakespawnpoints[ i ] = spawnstruct(); + fakespawnpoints[ i ].origin = ( ( min[ 0 ] * xamnt ) + ( max[ 0 ] * ( 1 - xamnt ) ), ( min[ 1 ] * yamnt ) + ( max[ 1 ] * ( 1 - yamnt ) ), min[ 2 ] ); + fakespawnpoints[ i ].angles = ( -1, -1, -1 ); + fakespawnpoints[ i ].forward = anglesToForward( fakespawnpoints[ i ].angles ); + fakespawnpoints[ i ].sighttracepoint = fakespawnpoints[ i ].origin; + i++; + x++; + } + y++; + } + didweights = 0; + while ( 1 ) + { + spawni = 0; + numiters = 5; + i = 0; + while ( i < numiters ) + { + if ( level.players.size && isDefined( level.players[ 0 ].team ) || level.players[ 0 ].team == "spectator" && !isDefined( level.players[ 0 ].class ) ) + { + break; + } + else + { + endspawni = spawni + ( fakespawnpoints.size / numiters ); + if ( i == ( numiters - 1 ) ) + { + endspawni = fakespawnpoints.size; + } + while ( spawni < endspawni ) + { + spawnpointupdate( fakespawnpoints[ spawni ] ); + spawni++; + } + if ( didweights ) + { + level.players[ 0 ] drawspawngraph( fakespawnpoints, w, h, weightscale ); + } + wait 0,05; + i++; + } + } + while ( level.players.size && isDefined( level.players[ 0 ].team ) || level.players[ 0 ].team == "spectator" && !isDefined( level.players[ 0 ].class ) ) + { + wait 1; + } + level.players[ 0 ] getspawnpoint_nearteam( fakespawnpoints ); + i = 0; + while ( i < fakespawnpoints.size ) + { + setupspawngraphpoint( fakespawnpoints[ i ], weightscale ); + i++; + } + didweights = 1; + level.players[ 0 ] drawspawngraph( fakespawnpoints, w, h, weightscale ); + wait 0,05; +#/ + } +} + +drawspawngraph( fakespawnpoints, w, h, weightscale ) +{ +/# + i = 0; + y = 0; + while ( y < h ) + { + yamnt = y / ( h - 1 ); + x = 0; + while ( x < w ) + { + xamnt = x / ( w - 1 ); + if ( y > 0 ) + { + spawngraphline( fakespawnpoints[ i ], fakespawnpoints[ i - w ], weightscale ); + } + if ( x > 0 ) + { + spawngraphline( fakespawnpoints[ i ], fakespawnpoints[ i - 1 ], weightscale ); + } + i++; + x++; + } + y++; +#/ + } +} + +setupspawngraphpoint( s1, weightscale ) +{ +/# + s1.visible = 1; + if ( s1.weight < ( -1000 / weightscale ) ) + { + s1.visible = 0; +#/ + } +} + +spawngraphline( s1, s2, weightscale ) +{ +/# + if ( !s1.visible || !s2.visible ) + { + return; + } + p1 = s1.origin + ( 0, 0, ( s1.weight * weightscale ) + 100 ); + p2 = s2.origin + ( 0, 0, ( s2.weight * weightscale ) + 100 ); + line( p1, p2, ( -1, -1, -1 ) ); +#/ +} + +loopbotspawns() +{ +/# + while ( 1 ) + { + while ( getDvarInt( "scr_killbots" ) < 1 ) + { + wait 3; + } + while ( !isDefined( level.players ) ) + { + wait 0,05; + } + bots = []; + i = 0; + while ( i < level.players.size ) + { + if ( !isDefined( level.players[ i ] ) ) + { + i++; + continue; + } + else + { + if ( level.players[ i ].sessionstate == "playing" && issubstr( level.players[ i ].name, "bot" ) ) + { + bots[ bots.size ] = level.players[ i ]; + } + } + i++; + } + while ( bots.size > 0 ) + { + if ( getDvarInt( "scr_killbots" ) == 1 ) + { + killer = bots[ randomint( bots.size ) ]; + victim = bots[ randomint( bots.size ) ]; + victim thread [[ level.callbackplayerdamage ]]( killer, killer, 1000, 0, "MOD_RIFLE_BULLET", "none", ( -1, -1, -1 ), ( -1, -1, -1 ), "none", 0, 0 ); + break; + } + else + { + numkills = getDvarInt( "scr_killbots" ); + lastvictim = undefined; + index = 0; + while ( index < numkills ) + { + killer = bots[ randomint( bots.size ) ]; + victim = bots[ randomint( bots.size ) ]; + while ( isDefined( lastvictim ) && victim == lastvictim ) + { + victim = bots[ randomint( bots.size ) ]; + } + victim thread [[ level.callbackplayerdamage ]]( killer, killer, 1000, 0, "MOD_RIFLE_BULLET", "none", ( -1, -1, -1 ), ( -1, -1, -1 ), "none", 0, 0 ); + lastvictim = victim; + index++; + } + } + } + if ( getDvar( "scr_killbottimer" ) != "" ) + { + wait getDvarFloat( "scr_killbottimer" ); + continue; + } + else + { + wait 0,05; + } +#/ + } +} + +allowspawndatareading() +{ +/# + setdvar( "scr_showspawnid", "" ); + prevval = getDvar( "scr_showspawnid" ); + prevrelval = getDvar( "scr_spawnidcycle" ); + readthistime = 0; + while ( 1 ) + { + val = getDvar( "scr_showspawnid" ); + relval = undefined; + while ( !isDefined( val ) || val == prevval ) + { + relval = getDvar( "scr_spawnidcycle" ); + if ( isDefined( relval ) && relval != "" ) + { + setdvar( "scr_spawnidcycle", "" ); + break; + } + else + { + wait 0,5; + } + } + prevval = val; + readthistime = 0; + readspawndata( val, relval ); + if ( !isDefined( level.curspawndata ) ) + { + println( "No spawn data to draw." ); + } + else + { + println( "Drawing spawn ID " + level.curspawndata.id ); + } + thread drawspawndata(); +#/ + } +} + +showdeathsdebug() +{ +/# + while ( 1 ) + { + while ( getDvar( "scr_spawnpointdebug" ) == "0" ) + { + wait 3; + } + time = getTime(); + i = 0; + while ( i < level.spawnlogic_deaths.size ) + { + if ( isDefined( level.spawnlogic_deaths[ i ].los ) ) + { + line( level.spawnlogic_deaths[ i ].org, level.spawnlogic_deaths[ i ].killorg, ( -1, -1, -1 ) ); + } + else + { + line( level.spawnlogic_deaths[ i ].org, level.spawnlogic_deaths[ i ].killorg, ( -1, -1, -1 ) ); + } + killer = level.spawnlogic_deaths[ i ].killer; + if ( isDefined( killer ) && isalive( killer ) ) + { + line( level.spawnlogic_deaths[ i ].killorg, killer.origin, ( 0,4, 0,4, 0,8 ) ); + } + i++; + } + p = 0; + while ( p < level.players.size ) + { + if ( !isDefined( level.players[ p ] ) ) + { + p++; + continue; + } + else + { + if ( isDefined( level.players[ p ].spawnlogic_killdist ) ) + { + print3d( level.players[ p ].origin + vectorScale( ( -1, -1, -1 ), 64 ), level.players[ p ].spawnlogic_killdist, ( -1, -1, -1 ) ); + } + } + p++; + } + oldspawnkills = level.spawnlogic_spawnkills; + level.spawnlogic_spawnkills = []; + i = 0; + while ( i < oldspawnkills.size ) + { + spawnkill = oldspawnkills[ i ]; + if ( spawnkill.dierwasspawner ) + { + line( spawnkill.spawnpointorigin, spawnkill.dierorigin, ( 0,4, 0,5, 0,4 ) ); + line( spawnkill.dierorigin, spawnkill.killerorigin, ( 0, 1, 1 ) ); + print3d( spawnkill.dierorigin + vectorScale( ( -1, -1, -1 ), 32 ), "SPAWNKILLED!", ( 0, 1, 1 ) ); + } + else + { + line( spawnkill.spawnpointorigin, spawnkill.killerorigin, ( 0,4, 0,5, 0,4 ) ); + line( spawnkill.killerorigin, spawnkill.dierorigin, ( 0, 1, 1 ) ); + print3d( spawnkill.dierorigin + vectorScale( ( -1, -1, -1 ), 32 ), "SPAWNDIED!", ( 0, 1, 1 ) ); + } + if ( ( time - spawnkill.time ) < 60000 ) + { + level.spawnlogic_spawnkills[ level.spawnlogic_spawnkills.size ] = oldspawnkills[ i ]; + } + i++; + } + wait 0,05; +#/ + } +} + +updatedeathinfodebug() +{ + while ( 1 ) + { + while ( getDvar( "scr_spawnpointdebug" ) == "0" ) + { + wait 3; + } + updatedeathinfo(); + wait 3; + } +} + +spawnweightdebug( spawnpoints ) +{ + level notify( "stop_spawn_weight_debug" ); + level endon( "stop_spawn_weight_debug" ); +/# + while ( 1 ) + { + while ( getDvar( "scr_spawnpointdebug" ) == "0" ) + { + wait 3; + } + textoffset = vectorScale( ( -1, -1, -1 ), 12 ); + i = 0; + while ( i < spawnpoints.size ) + { + amnt = 1 * ( 1 - ( spawnpoints[ i ].weight / -100000 ) ); + if ( amnt < 0 ) + { + amnt = 0; + } + if ( amnt > 1 ) + { + amnt = 1; + } + orig = spawnpoints[ i ].origin + vectorScale( ( -1, -1, -1 ), 80 ); + print3d( orig, int( spawnpoints[ i ].weight ), ( 1, amnt, 0,5 ) ); + orig += textoffset; + while ( isDefined( spawnpoints[ i ].spawndata ) ) + { + j = 0; + while ( j < spawnpoints[ i ].spawndata.size ) + { + print3d( orig, spawnpoints[ i ].spawndata[ j ], vectorScale( ( -1, -1, -1 ), 0,5 ) ); + orig += textoffset; + j++; + } + } + while ( isDefined( spawnpoints[ i ].sightchecks ) ) + { + j = 0; + while ( j < spawnpoints[ i ].sightchecks.size ) + { + if ( spawnpoints[ i ].sightchecks[ j ].penalty == 0 ) + { + j++; + continue; + } + else + { + print3d( orig, "Sight to enemy: -" + spawnpoints[ i ].sightchecks[ j ].penalty, vectorScale( ( -1, -1, -1 ), 0,5 ) ); + orig += textoffset; + } + j++; + } + } + i++; + } + wait 0,05; +#/ + } +} + +profiledebug() +{ + while ( 1 ) + { + while ( getDvar( #"6A99E750" ) != "1" ) + { + wait 3; + } + i = 0; + while ( i < level.spawnpoints.size ) + { + level.spawnpoints[ i ].weight = randomint( 10000 ); + i++; + } + if ( level.players.size > 0 ) + { + level.players[ randomint( level.players.size ) ] getspawnpoint_nearteam( level.spawnpoints ); + } + wait 0,05; + } +} + +debugnearbyplayers( players, origin ) +{ +/# + if ( getDvar( "scr_spawnpointdebug" ) == "0" ) + { + return; + } + starttime = getTime(); + while ( 1 ) + { + i = 0; + while ( i < players.size ) + { + line( players[ i ].origin, origin, ( 0,5, 1, 0,5 ) ); + i++; + } + if ( ( getTime() - starttime ) > 5000 ) + { + return; + } + wait 0,05; +#/ + } +} + +deathoccured( dier, killer ) +{ +} + +checkforsimilardeaths( deathinfo ) +{ + i = 0; + while ( i < level.spawnlogic_deaths.size ) + { + if ( level.spawnlogic_deaths[ i ].killer == deathinfo.killer ) + { + dist = distance( level.spawnlogic_deaths[ i ].org, deathinfo.org ); + if ( dist > 200 ) + { + i++; + continue; + } + else dist = distance( level.spawnlogic_deaths[ i ].killorg, deathinfo.killorg ); + if ( dist > 200 ) + { + i++; + continue; + } + else + { + level.spawnlogic_deaths[ i ].remove = 1; + } + } + i++; + } +} + +updatedeathinfo() +{ + time = getTime(); + i = 0; + while ( i < level.spawnlogic_deaths.size ) + { + deathinfo = level.spawnlogic_deaths[ i ]; + if ( ( time - deathinfo.time ) > 90000 && isDefined( deathinfo.killer ) && isalive( deathinfo.killer ) || !isDefined( level.teams[ deathinfo.killer.team ] ) && distance( deathinfo.killer.origin, deathinfo.killorg ) > 400 ) + { + level.spawnlogic_deaths[ i ].remove = 1; + } + i++; + } + oldarray = level.spawnlogic_deaths; + level.spawnlogic_deaths = []; + start = 0; + if ( ( oldarray.size - 1024 ) > 0 ) + { + start = oldarray.size - 1024; + } + i = start; + while ( i < oldarray.size ) + { + if ( !isDefined( oldarray[ i ].remove ) ) + { + level.spawnlogic_deaths[ level.spawnlogic_deaths.size ] = oldarray[ i ]; + } + i++; + } +} + +ispointvulnerable( playerorigin ) +{ + pos = self.origin + level.bettymodelcenteroffset; + playerpos = playerorigin + vectorScale( ( -1, -1, -1 ), 32 ); + distsqrd = distancesquared( pos, playerpos ); + forward = anglesToForward( self.angles ); + if ( distsqrd < ( level.bettydetectionradius * level.bettydetectionradius ) ) + { + playerdir = vectornormalize( playerpos - pos ); + angle = acos( vectordot( playerdir, forward ) ); + if ( angle < level.bettydetectionconeangle ) + { + return 1; + } + } + return 0; +} + +avoidweapondamage( spawnpoints ) +{ + if ( getDvar( #"0FB71FB7" ) == "0" ) + { + return; + } + weapondamagepenalty = 100000; + if ( getDvar( #"76B8F046" ) != "" && getDvar( #"76B8F046" ) != "0" ) + { + weapondamagepenalty = getDvarFloat( #"76B8F046" ); + } + mingrenadedistsquared = 62500; + i = 0; + while ( i < spawnpoints.size ) + { + j = 0; + while ( j < level.grenades.size ) + { + if ( !isDefined( level.grenades[ j ] ) ) + { + j++; + continue; + } + else + { + if ( distancesquared( spawnpoints[ i ].origin, level.grenades[ j ].origin ) < mingrenadedistsquared ) + { + spawnpoints[ i ].weight -= weapondamagepenalty; +/# + if ( level.storespawndata || level.debugspawning ) + { + spawnpoints[ i ].spawndata[ spawnpoints[ i ].spawndata.size ] = "Was near grenade: -" + int( weapondamagepenalty ); +#/ + } + } + } + j++; + } + i++; + } +} + +spawnperframeupdate() +{ + spawnpointindex = 0; + while ( 1 ) + { + wait 0,05; + if ( !isDefined( level.spawnpoints ) ) + { + return; + } + spawnpointindex = ( spawnpointindex + 1 ) % level.spawnpoints.size; + spawnpoint = level.spawnpoints[ spawnpointindex ]; + spawnpointupdate( spawnpoint ); + } +} + +getnonteamsum( skip_team, sums ) +{ + value = 0; + _a1986 = level.teams; + _k1986 = getFirstArrayKey( _a1986 ); + while ( isDefined( _k1986 ) ) + { + team = _a1986[ _k1986 ]; + if ( team == skip_team ) + { + } + else + { + value += sums[ team ]; + } + _k1986 = getNextArrayKey( _a1986, _k1986 ); + } + return value; +} + +getnonteammindist( skip_team, mindists ) +{ + dist = 9999999; + _a2000 = level.teams; + _k2000 = getFirstArrayKey( _a2000 ); + while ( isDefined( _k2000 ) ) + { + team = _a2000[ _k2000 ]; + if ( team == skip_team ) + { + } + else + { + if ( dist > mindists[ team ] ) + { + dist = mindists[ team ]; + } + } + _k2000 = getNextArrayKey( _a2000, _k2000 ); + } + return dist; +} + +spawnpointupdate( spawnpoint ) +{ + if ( level.teambased ) + { + sights = []; + _a2018 = level.teams; + _k2018 = getFirstArrayKey( _a2018 ); + while ( isDefined( _k2018 ) ) + { + team = _a2018[ _k2018 ]; + spawnpoint.enemysights[ team ] = 0; + sights[ team ] = 0; + spawnpoint.nearbyplayers[ team ] = []; + _k2018 = getNextArrayKey( _a2018, _k2018 ); + } + } + else spawnpoint.enemysights = 0; + spawnpoint.nearbyplayers[ "all" ] = []; + spawnpointdir = spawnpoint.forward; + debug = 0; +/# + debug = getDvarInt( "scr_spawnpointdebug" ) > 0; +#/ + mindist = []; + distsum = []; + if ( !level.teambased ) + { + mindist[ "all" ] = 9999999; + } + _a2047 = level.teams; + _k2047 = getFirstArrayKey( _a2047 ); + while ( isDefined( _k2047 ) ) + { + team = _a2047[ _k2047 ]; + spawnpoint.distsum[ team ] = 0; + spawnpoint.enemydistsum[ team ] = 0; + spawnpoint.minenemydist[ team ] = 9999999; + mindist[ team ] = 9999999; + _k2047 = getNextArrayKey( _a2047, _k2047 ); + } + spawnpoint.numplayersatlastupdate = 0; + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( player.sessionstate != "playing" ) + { + i++; + continue; + } + else diff = player.origin - spawnpoint.origin; + diff = ( diff[ 0 ], diff[ 1 ], 0 ); + dist = length( diff ); + team = "all"; + if ( level.teambased ) + { + team = player.team; + } + if ( dist < 1024 ) + { + spawnpoint.nearbyplayers[ team ][ spawnpoint.nearbyplayers[ team ].size ] = player; + } + if ( dist < mindist[ team ] ) + { + mindist[ team ] = dist; + } + distsum[ team ] += dist; + spawnpoint.numplayersatlastupdate++; + pdir = anglesToForward( player.angles ); + if ( vectordot( spawnpointdir, diff ) < 0 && vectordot( pdir, diff ) > 0 ) + { + i++; + continue; + } + else + { + losexists = bullettracepassed( player.origin + vectorScale( ( -1, -1, -1 ), 50 ), spawnpoint.sighttracepoint, 0, undefined ); + spawnpoint.lastsighttracetime = getTime(); + if ( losexists ) + { + if ( level.teambased ) + { + sights[ player.team ]++; + } + else + { + spawnpoint.enemysights++; + } +/# + if ( debug ) + { + line( player.origin + vectorScale( ( -1, -1, -1 ), 50 ), spawnpoint.sighttracepoint, ( 0,5, 1, 0,5 ) ); +#/ + } + } + } + i++; + } + if ( level.teambased ) + { + _a2128 = level.teams; + _k2128 = getFirstArrayKey( _a2128 ); + while ( isDefined( _k2128 ) ) + { + team = _a2128[ _k2128 ]; + spawnpoint.enemysights[ team ] = getnonteamsum( team, sights ); + spawnpoint.minenemydist[ team ] = getnonteammindist( team, mindist ); + spawnpoint.distsum[ team ] = distsum[ team ]; + spawnpoint.enemydistsum[ team ] = getnonteamsum( team, distsum ); + _k2128 = getNextArrayKey( _a2128, _k2128 ); + } + } + else spawnpoint.distsum[ "all" ] = distsum[ "all" ]; + spawnpoint.enemydistsum[ "all" ] = distsum[ "all" ]; + spawnpoint.minenemydist[ "all" ] = mindist[ "all" ]; +} + +getlospenalty() +{ + if ( getDvar( #"CACDB8AA" ) != "" && getDvar( #"CACDB8AA" ) != "0" ) + { + return getDvarFloat( #"CACDB8AA" ); + } + return 100000; +} + +lastminutesighttraces( spawnpoint ) +{ + if ( !isDefined( spawnpoint.nearbyplayers ) ) + { + return 0; + } + closest = undefined; + closestdistsq = undefined; + secondclosest = undefined; + secondclosestdistsq = undefined; + _a2162 = spawnpoint.nearbyplayers; + _k2162 = getFirstArrayKey( _a2162 ); + while ( isDefined( _k2162 ) ) + { + team = _a2162[ _k2162 ]; + if ( team == self.team ) + { + } + else + { + i = 0; + while ( i < spawnpoint.nearbyplayers[ team ].size ) + { + player = spawnpoint.nearbyplayers[ team ][ i ]; + if ( !isDefined( player ) ) + { + i++; + continue; + } + else if ( player.sessionstate != "playing" ) + { + i++; + continue; + } + else if ( player == self ) + { + i++; + continue; + } + else distsq = distancesquared( spawnpoint.origin, player.origin ); + if ( !isDefined( closest ) || distsq < closestdistsq ) + { + secondclosest = closest; + secondclosestdistsq = closestdistsq; + closest = player; + closestdistsq = distsq; + i++; + continue; + } + else + { + if ( !isDefined( secondclosest ) || distsq < secondclosestdistsq ) + { + secondclosest = player; + secondclosestdistsq = distsq; + } + } + i++; + } + } + _k2162 = getNextArrayKey( _a2162, _k2162 ); + } + if ( isDefined( closest ) ) + { + if ( bullettracepassed( closest.origin + vectorScale( ( -1, -1, -1 ), 50 ), spawnpoint.sighttracepoint, 0, undefined ) ) + { + return 1; + } + } + if ( isDefined( secondclosest ) ) + { + if ( bullettracepassed( secondclosest.origin + vectorScale( ( -1, -1, -1 ), 50 ), spawnpoint.sighttracepoint, 0, undefined ) ) + { + return 1; + } + } + return 0; +} + +avoidvisibleenemies( spawnpoints, teambased ) +{ + if ( getDvar( #"0FB71FB7" ) == "0" ) + { + return; + } + lospenalty = getlospenalty(); + mindistteam = self.team; + if ( teambased ) + { + i = 0; + while ( i < spawnpoints.size ) + { + if ( !isDefined( spawnpoints[ i ].enemysights ) ) + { + i++; + continue; + } + else + { + penalty = lospenalty * spawnpoints[ i ].enemysights[ self.team ]; + spawnpoints[ i ].weight -= penalty; +/# + if ( level.storespawndata || level.debugspawning ) + { + index = spawnpoints[ i ].sightchecks.size; + spawnpoints[ i ].sightchecks[ index ] = spawnstruct(); + spawnpoints[ i ].sightchecks[ index ].penalty = penalty; +#/ + } + } + i++; + } + } + else i = 0; + while ( i < spawnpoints.size ) + { + if ( !isDefined( spawnpoints[ i ].enemysights ) ) + { + i++; + continue; + } + else + { + penalty = lospenalty * spawnpoints[ i ].enemysights; + spawnpoints[ i ].weight -= penalty; +/# + if ( level.storespawndata || level.debugspawning ) + { + index = spawnpoints[ i ].sightchecks.size; + spawnpoints[ i ].sightchecks[ index ] = spawnstruct(); + spawnpoints[ i ].sightchecks[ index ].penalty = penalty; +#/ + } + } + i++; + } + mindistteam = "all"; + avoidweight = getDvarFloat( "scr_spawn_enemyavoidweight" ); + while ( avoidweight != 0 ) + { + nearbyenemyouterrange = getDvarFloat( "scr_spawn_enemyavoiddist" ); + nearbyenemyouterrangesq = nearbyenemyouterrange * nearbyenemyouterrange; + nearbyenemypenalty = 1500 * avoidweight; + nearbyenemyminorpenalty = 800 * avoidweight; + lastattackerorigin = vectorScale( ( -1, -1, -1 ), 99999 ); + lastdeathpos = vectorScale( ( -1, -1, -1 ), 99999 ); + if ( isalive( self.lastattacker ) ) + { + lastattackerorigin = self.lastattacker.origin; + } + if ( isDefined( self.lastdeathpos ) ) + { + lastdeathpos = self.lastdeathpos; + } + i = 0; + while ( i < spawnpoints.size ) + { + mindist = spawnpoints[ i ].minenemydist[ mindistteam ]; + if ( mindist < ( nearbyenemyouterrange * 2 ) ) + { + penalty = nearbyenemyminorpenalty * ( 1 - ( mindist / ( nearbyenemyouterrange * 2 ) ) ); + if ( mindist < nearbyenemyouterrange ) + { + penalty += nearbyenemypenalty * ( 1 - ( mindist / nearbyenemyouterrange ) ); + } + if ( penalty > 0 ) + { + spawnpoints[ i ].weight -= penalty; +/# + if ( level.storespawndata || level.debugspawning ) + { + spawnpoints[ i ].spawndata[ spawnpoints[ i ].spawndata.size ] = "Nearest enemy at " + int( spawnpoints[ i ].minenemydist[ mindistteam ] ) + " units: -" + int( penalty ); +#/ + } + } + } + i++; + } + } +} + +avoidspawnreuse( spawnpoints, teambased ) +{ + if ( getDvar( #"0FB71FB7" ) == "0" ) + { + return; + } + time = getTime(); + maxtime = 10000; + maxdistsq = 1048576; + i = 0; + while ( i < spawnpoints.size ) + { + spawnpoint = spawnpoints[ i ]; + if ( isDefined( spawnpoint.lastspawnedplayer ) || !isDefined( spawnpoint.lastspawntime ) && !isalive( spawnpoint.lastspawnedplayer ) ) + { + i++; + continue; + } + else + { + if ( spawnpoint.lastspawnedplayer == self ) + { + i++; + continue; + } + else if ( teambased && spawnpoint.lastspawnedplayer.team == self.team ) + { + i++; + continue; + } + else + { + timepassed = time - spawnpoint.lastspawntime; + if ( timepassed < maxtime ) + { + distsq = distancesquared( spawnpoint.lastspawnedplayer.origin, spawnpoint.origin ); + if ( distsq < maxdistsq ) + { + worsen = ( 5000 * ( 1 - ( distsq / maxdistsq ) ) ) * ( 1 - ( timepassed / maxtime ) ); + spawnpoint.weight -= worsen; +/# + if ( level.storespawndata || level.debugspawning ) + { + spawnpoint.spawndata[ spawnpoint.spawndata.size ] = "Was recently used: -" + worsen; +#/ + } + } + else + { + spawnpoint.lastspawnedplayer = undefined; + } + i++; + continue; + } + else + { + spawnpoint.lastspawnedplayer = undefined; + } + } + } + i++; + } +} + +avoidsamespawn( spawnpoints ) +{ + if ( getDvar( #"0FB71FB7" ) == "0" ) + { + return; + } + if ( !isDefined( self.lastspawnpoint ) ) + { + return; + } + i = 0; + while ( i < spawnpoints.size ) + { + if ( spawnpoints[ i ] == self.lastspawnpoint ) + { + spawnpoints[ i ].weight -= 50000; +/# + if ( level.storespawndata || level.debugspawning ) + { + spawnpoints[ i ].spawndata[ spawnpoints[ i ].spawndata.size ] = "Was last spawnpoint: -50000"; +#/ + } + return; + } + else + { + i++; + } + } +} + +getrandomintermissionpoint() +{ + spawnpoints = getentarray( "mp_global_intermission", "classname" ); + if ( !spawnpoints.size ) + { + spawnpoints = getentarray( "info_player_start", "classname" ); + } +/# + assert( spawnpoints.size ); +#/ + spawnpoint = maps/mp/gametypes_zm/_spawnlogic::getspawnpoint_random( spawnpoints ); + return spawnpoint; +} diff --git a/patch_zm/maps/mp/gametypes_zm/_spectating.gsc b/patch_zm/maps/mp/gametypes_zm/_spectating.gsc new file mode 100644 index 0000000..31ce9f4 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_spectating.gsc @@ -0,0 +1,276 @@ + +init() +{ + _a3 = level.teams; + _k3 = getFirstArrayKey( _a3 ); + while ( isDefined( _k3 ) ) + { + team = _a3[ _k3 ]; + level.spectateoverride[ team ] = spawnstruct(); + _k3 = getNextArrayKey( _a3, _k3 ); + } + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onjoinedteam(); + player thread onjoinedspectators(); + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self setspectatepermissions(); + } +} + +onjoinedteam() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_team" ); + self setspectatepermissionsformachine(); + } +} + +onjoinedspectators() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_spectators" ); + self setspectatepermissionsformachine(); + } +} + +updatespectatesettings() +{ + level endon( "game_ended" ); + index = 0; + while ( index < level.players.size ) + { + level.players[ index ] setspectatepermissions(); + index++; + } +} + +getsplitscreenteam() +{ + index = 0; + while ( index < level.players.size ) + { + if ( !isDefined( level.players[ index ] ) ) + { + index++; + continue; + } + else if ( level.players[ index ] == self ) + { + index++; + continue; + } + else if ( !self isplayeronsamemachine( level.players[ index ] ) ) + { + index++; + continue; + } + else + { + team = level.players[ index ].sessionteam; + if ( team != "spectator" ) + { + return team; + } + } + index++; + } + return self.sessionteam; +} + +otherlocalplayerstillalive() +{ + index = 0; + while ( index < level.players.size ) + { + if ( !isDefined( level.players[ index ] ) ) + { + index++; + continue; + } + else if ( level.players[ index ] == self ) + { + index++; + continue; + } + else if ( !self isplayeronsamemachine( level.players[ index ] ) ) + { + index++; + continue; + } + else + { + if ( isalive( level.players[ index ] ) ) + { + return 1; + } + } + index++; + } + return 0; +} + +allowspectateallteams( allow ) +{ + _a114 = level.teams; + _k114 = getFirstArrayKey( _a114 ); + while ( isDefined( _k114 ) ) + { + team = _a114[ _k114 ]; + self allowspectateteam( team, allow ); + _k114 = getNextArrayKey( _a114, _k114 ); + } +} + +allowspectateallteamsexceptteam( skip_team, allow ) +{ + _a122 = level.teams; + _k122 = getFirstArrayKey( _a122 ); + while ( isDefined( _k122 ) ) + { + team = _a122[ _k122 ]; + if ( team == skip_team ) + { + } + else + { + self allowspectateteam( team, allow ); + } + _k122 = getNextArrayKey( _a122, _k122 ); + } +} + +setspectatepermissions() +{ + team = self.sessionteam; + if ( team == "spectator" ) + { + if ( self issplitscreen() && !level.splitscreen ) + { + team = getsplitscreenteam(); + } + if ( team == "spectator" ) + { + self allowspectateallteams( 1 ); + self allowspectateteam( "freelook", 0 ); + self allowspectateteam( "none", 1 ); + self allowspectateteam( "localplayers", 1 ); + return; + } + } + spectatetype = level.spectatetype; + switch( spectatetype ) + { + case 0: + self allowspectateallteams( 0 ); + self allowspectateteam( "freelook", 0 ); + self allowspectateteam( "none", 1 ); + self allowspectateteam( "localplayers", 0 ); + break; + case 3: + if ( self issplitscreen() && self otherlocalplayerstillalive() ) + { + self allowspectateallteams( 0 ); + self allowspectateteam( "none", 0 ); + self allowspectateteam( "freelook", 0 ); + self allowspectateteam( "localplayers", 1 ); + break; + } + else + { + case 1: + if ( !level.teambased ) + { + self allowspectateallteams( 1 ); + self allowspectateteam( "none", 1 ); + self allowspectateteam( "freelook", 0 ); + self allowspectateteam( "localplayers", 1 ); + } + else if ( isDefined( team ) && isDefined( level.teams[ team ] ) ) + { + self allowspectateteam( team, 1 ); + self allowspectateallteamsexceptteam( team, 0 ); + self allowspectateteam( "freelook", 0 ); + self allowspectateteam( "none", 0 ); + self allowspectateteam( "localplayers", 1 ); + } + else + { + self allowspectateallteams( 0 ); + self allowspectateteam( "freelook", 0 ); + self allowspectateteam( "none", 0 ); + self allowspectateteam( "localplayers", 1 ); + } + break; + case 2: + self allowspectateallteams( 1 ); + self allowspectateteam( "freelook", 1 ); + self allowspectateteam( "none", 1 ); + self allowspectateteam( "localplayers", 1 ); + break; + } + } + if ( isDefined( team ) && isDefined( level.teams[ team ] ) ) + { + if ( isDefined( level.spectateoverride[ team ].allowfreespectate ) ) + { + self allowspectateteam( "freelook", 1 ); + } + if ( isDefined( level.spectateoverride[ team ].allowenemyspectate ) ) + { + self allowspectateallteamsexceptteam( team, 1 ); + } + } +} + +setspectatepermissionsformachine() +{ + self setspectatepermissions(); + if ( !self issplitscreen() ) + { + return; + } + index = 0; + while ( index < level.players.size ) + { + if ( !isDefined( level.players[ index ] ) ) + { + index++; + continue; + } + else if ( level.players[ index ] == self ) + { + index++; + continue; + } + else if ( !self isplayeronsamemachine( level.players[ index ] ) ) + { + index++; + continue; + } + else + { + level.players[ index ] setspectatepermissions(); + } + index++; + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_tweakables.gsc b/patch_zm/maps/mp/gametypes_zm/_tweakables.gsc new file mode 100644 index 0000000..4b85e4a --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_tweakables.gsc @@ -0,0 +1,394 @@ +#include maps/mp/_utility; + +gettweakabledvarvalue( category, name ) +{ + switch( category ) + { + case "rule": + dvar = level.rules[ name ].dvar; + break; + case "game": + dvar = level.gametweaks[ name ].dvar; + break; + case "team": + dvar = level.teamtweaks[ name ].dvar; + break; + case "player": + dvar = level.playertweaks[ name ].dvar; + break; + case "class": + dvar = level.classtweaks[ name ].dvar; + break; + case "weapon": + dvar = level.weapontweaks[ name ].dvar; + break; + case "killstreak": + dvar = level.hardpointtweaks[ name ].dvar; + break; + case "hud": + dvar = level.hudtweaks[ name ].dvar; + break; + default: + dvar = undefined; + break; + } +/# + assert( isDefined( dvar ) ); +#/ + value = getDvarInt( dvar ); + return value; +} + +gettweakabledvar( category, name ) +{ + switch( category ) + { + case "rule": + value = level.rules[ name ].dvar; + break; + case "game": + value = level.gametweaks[ name ].dvar; + break; + case "team": + value = level.teamtweaks[ name ].dvar; + break; + case "player": + value = level.playertweaks[ name ].dvar; + break; + case "class": + value = level.classtweaks[ name ].dvar; + break; + case "weapon": + value = level.weapontweaks[ name ].dvar; + break; + case "killstreak": + value = level.hardpointtweaks[ name ].dvar; + break; + case "hud": + value = level.hudtweaks[ name ].dvar; + break; + default: + value = undefined; + break; + } +/# + assert( isDefined( value ) ); +#/ + return value; +} + +gettweakablevalue( category, name ) +{ + switch( category ) + { + case "rule": + value = level.rules[ name ].value; + break; + case "game": + value = level.gametweaks[ name ].value; + break; + case "team": + value = level.teamtweaks[ name ].value; + break; + case "player": + value = level.playertweaks[ name ].value; + break; + case "class": + value = level.classtweaks[ name ].value; + break; + case "weapon": + value = level.weapontweaks[ name ].value; + break; + case "killstreak": + value = level.hardpointtweaks[ name ].value; + break; + case "hud": + value = level.hudtweaks[ name ].value; + break; + default: + value = undefined; + break; + } + overridedvar = "scr_" + level.gametype + "_" + category + "_" + name; + if ( getDvar( overridedvar ) != "" ) + { + return getDvarInt( overridedvar ); + } +/# + assert( isDefined( value ) ); +#/ + return value; +} + +gettweakablelastvalue( category, name ) +{ + switch( category ) + { + case "rule": + value = level.rules[ name ].lastvalue; + break; + case "game": + value = level.gametweaks[ name ].lastvalue; + break; + case "team": + value = level.teamtweaks[ name ].lastvalue; + break; + case "player": + value = level.playertweaks[ name ].lastvalue; + break; + case "class": + value = level.classtweaks[ name ].lastvalue; + break; + case "weapon": + value = level.weapontweaks[ name ].lastvalue; + break; + case "killstreak": + value = level.hardpointtweaks[ name ].lastvalue; + break; + case "hud": + value = level.hudtweaks[ name ].lastvalue; + break; + default: + value = undefined; + break; + } +/# + assert( isDefined( value ) ); +#/ + return value; +} + +settweakablevalue( category, name, value ) +{ + switch( category ) + { + case "rule": + dvar = level.rules[ name ].dvar; + break; + case "game": + dvar = level.gametweaks[ name ].dvar; + break; + case "team": + dvar = level.teamtweaks[ name ].dvar; + break; + case "player": + dvar = level.playertweaks[ name ].dvar; + break; + case "class": + dvar = level.classtweaks[ name ].dvar; + break; + case "weapon": + dvar = level.weapontweaks[ name ].dvar; + break; + case "killstreak": + dvar = level.hardpointtweaks[ name ].dvar; + break; + case "hud": + dvar = level.hudtweaks[ name ].dvar; + break; + default: + dvar = undefined; + break; + } + setdvar( dvar, value ); +} + +settweakablelastvalue( category, name, value ) +{ + switch( category ) + { + case "rule": + level.rules[ name ].lastvalue = value; + break; + case "game": + level.gametweaks[ name ].lastvalue = value; + break; + case "team": + level.teamtweaks[ name ].lastvalue = value; + break; + case "player": + level.playertweaks[ name ].lastvalue = value; + break; + case "class": + level.classtweaks[ name ].lastvalue = value; + break; + case "weapon": + level.weapontweaks[ name ].lastvalue = value; + break; + case "killstreak": + level.hardpointtweaks[ name ].lastvalue = value; + break; + case "hud": + level.hudtweaks[ name ].lastvalue = value; + break; + default: + } + } +} + +registertweakable( category, name, dvar, value ) +{ + if ( isstring( value ) ) + { + if ( getDvar( dvar ) == "" ) + { + setdvar( dvar, value ); + } + else + { + value = getDvar( dvar ); + } + } + else if ( getDvar( dvar ) == "" ) + { + setdvar( dvar, value ); + } + else + { + value = getDvarInt( dvar ); + } + switch( category ) + { + case "rule": + if ( !isDefined( level.rules[ name ] ) ) + { + level.rules[ name ] = spawnstruct(); + } + level.rules[ name ].value = value; + level.rules[ name ].lastvalue = value; + level.rules[ name ].dvar = dvar; + break; + case "game": + if ( !isDefined( level.gametweaks[ name ] ) ) + { + level.gametweaks[ name ] = spawnstruct(); + } + level.gametweaks[ name ].value = value; + level.gametweaks[ name ].lastvalue = value; + level.gametweaks[ name ].dvar = dvar; + break; + case "team": + if ( !isDefined( level.teamtweaks[ name ] ) ) + { + level.teamtweaks[ name ] = spawnstruct(); + } + level.teamtweaks[ name ].value = value; + level.teamtweaks[ name ].lastvalue = value; + level.teamtweaks[ name ].dvar = dvar; + break; + case "player": + if ( !isDefined( level.playertweaks[ name ] ) ) + { + level.playertweaks[ name ] = spawnstruct(); + } + level.playertweaks[ name ].value = value; + level.playertweaks[ name ].lastvalue = value; + level.playertweaks[ name ].dvar = dvar; + break; + case "class": + if ( !isDefined( level.classtweaks[ name ] ) ) + { + level.classtweaks[ name ] = spawnstruct(); + } + level.classtweaks[ name ].value = value; + level.classtweaks[ name ].lastvalue = value; + level.classtweaks[ name ].dvar = dvar; + break; + case "weapon": + if ( !isDefined( level.weapontweaks[ name ] ) ) + { + level.weapontweaks[ name ] = spawnstruct(); + } + level.weapontweaks[ name ].value = value; + level.weapontweaks[ name ].lastvalue = value; + level.weapontweaks[ name ].dvar = dvar; + break; + case "killstreak": + if ( !isDefined( level.hardpointtweaks[ name ] ) ) + { + level.hardpointtweaks[ name ] = spawnstruct(); + } + level.hardpointtweaks[ name ].value = value; + level.hardpointtweaks[ name ].lastvalue = value; + level.hardpointtweaks[ name ].dvar = dvar; + break; + case "hud": + if ( !isDefined( level.hudtweaks[ name ] ) ) + { + level.hudtweaks[ name ] = spawnstruct(); + } + level.hudtweaks[ name ].value = value; + level.hudtweaks[ name ].lastvalue = value; + level.hudtweaks[ name ].dvar = dvar; + break; + } +} + +init() +{ + level.clienttweakables = []; + level.tweakablesinitialized = 1; + level.rules = []; + level.gametweaks = []; + level.teamtweaks = []; + level.playertweaks = []; + level.classtweaks = []; + level.weapontweaks = []; + level.hardpointtweaks = []; + level.hudtweaks = []; + registertweakable( "game", "arcadescoring", "scr_game_arcadescoring", 0 ); + registertweakable( "game", "difficulty", "scr_game_difficulty", 1 ); + registertweakable( "game", "pinups", "scr_game_pinups", 0 ); + registertweakable( "team", "teamkillerplaylistbanquantum", "scr_team_teamkillerplaylistbanquantum", 0 ); + registertweakable( "team", "teamkillerplaylistbanpenalty", "scr_team_teamkillerplaylistbanpenalty", 0 ); + registertweakable( "player", "allowrevive", "scr_player_allowrevive", 1 ); + registertweakable( "weapon", "allowfrag", "scr_weapon_allowfrags", 1 ); + registertweakable( "weapon", "allowsmoke", "scr_weapon_allowsmoke", 1 ); + registertweakable( "weapon", "allowflash", "scr_weapon_allowflash", 1 ); + registertweakable( "weapon", "allowc4", "scr_weapon_allowc4", 1 ); + registertweakable( "weapon", "allowsatchel", "scr_weapon_allowsatchel", 1 ); + registertweakable( "weapon", "allowbetty", "scr_weapon_allowbetty", 1 ); + registertweakable( "weapon", "allowrpgs", "scr_weapon_allowrpgs", 1 ); + registertweakable( "weapon", "allowmines", "scr_weapon_allowmines", 1 ); + registertweakable( "hud", "showobjicons", "ui_hud_showobjicons", 1 ); + setclienttweakable( "hud", "showobjicons" ); + registertweakable( "killstreak", "allowradar", "scr_hardpoint_allowradar", 1 ); + registertweakable( "killstreak", "allowradardirection", "scr_hardpoint_allowradardirection", 1 ); + registertweakable( "killstreak", "allowcounteruav", "scr_hardpoint_allowcounteruav", 1 ); + registertweakable( "killstreak", "allowdogs", "scr_hardpoint_allowdogs", 1 ); + registertweakable( "killstreak", "allowhelicopter_comlink", "scr_hardpoint_allowhelicopter_comlink", 1 ); + registertweakable( "killstreak", "allowrcbomb", "scr_hardpoint_allowrcbomb", 1 ); + registertweakable( "killstreak", "allowauto_turret", "scr_hardpoint_allowauto_turret", 1 ); + level thread updateuitweakables(); +} + +setclienttweakable( category, name ) +{ + level.clienttweakables[ level.clienttweakables.size ] = name; +} + +updateuitweakables() +{ + for ( ;; ) + { + index = 0; + while ( index < level.clienttweakables.size ) + { + clienttweakable = level.clienttweakables[ index ]; + curvalue = gettweakabledvarvalue( "hud", clienttweakable ); + lastvalue = gettweakablelastvalue( "hud", clienttweakable ); + if ( curvalue != lastvalue ) + { + updateserverdvar( gettweakabledvar( "hud", clienttweakable ), curvalue ); + settweakablelastvalue( "hud", clienttweakable, curvalue ); + } + index++; + } + wait 1; + } +} + +updateserverdvar( dvar, value ) +{ + makedvarserverinfo( dvar, value ); +} diff --git a/patch_zm/maps/mp/gametypes_zm/_weapon_utils.gsc b/patch_zm/maps/mp/gametypes_zm/_weapon_utils.gsc new file mode 100644 index 0000000..7359766 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_weapon_utils.gsc @@ -0,0 +1,119 @@ +#include maps/mp/_utility; +#include common_scripts/utility; + +isgrenadelauncherweapon( weapon ) +{ + if ( getsubstr( weapon, 0, 3 ) == "gl_" ) + { + return 1; + } + switch( weapon ) + { + case "china_lake_mp": + case "xm25_mp": + return 1; + default: + return 0; + } +} + +isdumbrocketlauncherweapon( weapon ) +{ + switch( weapon ) + { + case "m220_tow_mp": + case "rpg_mp": + return 1; + default: + return 0; + } +} + +isguidedrocketlauncherweapon( weapon ) +{ + switch( weapon ) + { + case "fhj18_mp": + case "javelin_mp": + case "m202_flash_mp": + case "m72_law_mp": + case "smaw_mp": + return 1; + default: + return 0; + } +} + +isrocketlauncherweapon( weapon ) +{ + if ( isdumbrocketlauncherweapon( weapon ) ) + { + return 1; + } + if ( isguidedrocketlauncherweapon( weapon ) ) + { + return 1; + } + return 0; +} + +islauncherweapon( weapon ) +{ + if ( isrocketlauncherweapon( weapon ) ) + { + return 1; + } + if ( isgrenadelauncherweapon( weapon ) ) + { + return 1; + } + return 0; +} + +isreducedteamkillweapon( weapon ) +{ + switch( weapon ) + { + case "planemortar_mp": + return 1; + default: + return 0; + } +} + +ishackweapon( weapon ) +{ + return 0; +} + +ispistol( weapon ) +{ + return isDefined( level.side_arm_array[ weapon ] ); +} + +isflashorstunweapon( weapon ) +{ + if ( isDefined( weapon ) ) + { + switch( weapon ) + { + case "concussion_grenade_mp": + case "flash_grenade_mp": + case "proximity_grenade_aoe_mp": + case "proximity_grenade_mp": + return 1; + } + } + return 0; +} + +isflashorstundamage( weapon, meansofdeath ) +{ + if ( isflashorstunweapon( weapon ) ) + { + if ( meansofdeath != "MOD_GRENADE_SPLASH" ) + { + return meansofdeath == "MOD_GAS"; + } + } +} diff --git a/patch_zm/maps/mp/gametypes_zm/_weaponobjects.gsc b/patch_zm/maps/mp/gametypes_zm/_weaponobjects.gsc new file mode 100644 index 0000000..8953fc5 --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_weaponobjects.gsc @@ -0,0 +1,2435 @@ +#include maps/mp/gametypes_zm/_globallogic_audio; +#include maps/mp/gametypes_zm/_damagefeedback; +#include maps/mp/gametypes_zm/_globallogic_player; +#include maps/mp/gametypes_zm/_weaponobjects; +#include maps/mp/_challenges; +#include maps/mp/_ballistic_knife; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ +/# + debug = weapons_get_dvar_int( "scr_weaponobject_debug", "0" ); +#/ + coneangle = weapons_get_dvar_int( "scr_weaponobject_coneangle", "70" ); + mindist = weapons_get_dvar_int( "scr_weaponobject_mindist", "20" ); + graceperiod = weapons_get_dvar( "scr_weaponobject_graceperiod", "0.6" ); + radius = weapons_get_dvar_int( "scr_weaponobject_radius", "192" ); + level thread onplayerconnect(); + level.watcherweapons = []; + level.watcherweapons = getwatcherweapons(); + level.watcherweaponnames = []; + level.watcherweaponnames = getwatchernames( level.watcherweapons ); + level.retrievableweapons = []; + level.retrievableweapons = getretrievableweapons(); + level.retrievableweaponnames = []; + level.retrievableweaponnames = getwatchernames( level.retrievableweapons ); + level.weaponobjects_headicon_offset = []; + level.weaponobjects_headicon_offset[ "default" ] = vectorScale( ( 0, 0, 1 ), 20 ); + level.weaponobjectexplodethisframe = 0; + if ( getDvar( "scr_deleteexplosivesonspawn" ) == "" ) + { + setdvar( "scr_deleteexplosivesonspawn", 1 ); + } + level.deleteexplosivesonspawn = getDvarInt( "scr_deleteexplosivesonspawn" ); + if ( sessionmodeiszombiesgame() ) + { + return; + } + precachestring( &"MP_DEFUSING_EXPLOSIVE" ); + level.claymorefxid = loadfx( "weapon/claymore/fx_claymore_laser" ); + level._equipment_spark_fx = loadfx( "weapon/grenade/fx_spark_disabled_weapon" ); + level._equipment_emp_destroy_fx = loadfx( "weapon/emp/fx_emp_explosion_equip" ); + level._equipment_explode_fx = loadfx( "explosions/fx_exp_equipment" ); + level._equipment_explode_fx_lg = loadfx( "explosions/fx_exp_equipment_lg" ); + level._effect[ "powerLight" ] = loadfx( "weapon/crossbow/fx_trail_crossbow_blink_red_os" ); + setupretrievablehintstrings(); + level.weaponobjects_headicon_offset[ "acoustic_sensor_mp" ] = vectorScale( ( 0, 0, 1 ), 25 ); + level.weaponobjects_headicon_offset[ "sensor_grenade_mp" ] = vectorScale( ( 0, 0, 1 ), 25 ); + level.weaponobjects_headicon_offset[ "camera_spike_mp" ] = vectorScale( ( 0, 0, 1 ), 35 ); + level.weaponobjects_headicon_offset[ "claymore_mp" ] = vectorScale( ( 0, 0, 1 ), 20 ); + level.weaponobjects_headicon_offset[ "bouncingbetty_mp" ] = vectorScale( ( 0, 0, 1 ), 20 ); + level.weaponobjects_headicon_offset[ "satchel_charge_mp" ] = vectorScale( ( 0, 0, 1 ), 10 ); + level.weaponobjects_headicon_offset[ "scrambler_mp" ] = vectorScale( ( 0, 0, 1 ), 20 ); + level.weaponobjects_headicon_offset[ "trophy_system_mp" ] = vectorScale( ( 0, 0, 1 ), 20 ); + level.weaponobjects_hacker_trigger_width = 32; + level.weaponobjects_hacker_trigger_height = 32; +} + +getwatchernames( weapons ) +{ + names = []; + _a73 = weapons; + index = getFirstArrayKey( _a73 ); + while ( isDefined( index ) ) + { + weapon = _a73[ index ]; + names[ index ] = getsubstr( weapon, 0, weapon.size - 3 ); + index = getNextArrayKey( _a73, index ); + } + return names; +} + +weapons_get_dvar_int( dvar, def ) +{ + return int( weapons_get_dvar( dvar, def ) ); +} + +weapons_get_dvar( dvar, def ) +{ + if ( getDvar( dvar ) != "" ) + { + return getDvarFloat( dvar ); + } + else + { + setdvar( dvar, def ); + return def; + } +} + +setupretrievablehintstrings() +{ + createretrievablehint( "hatchet", &"MP_HATCHET_PICKUP" ); + createretrievablehint( "claymore", &"MP_CLAYMORE_PICKUP" ); + createretrievablehint( "bouncingbetty", &"MP_BOUNCINGBETTY_PICKUP" ); + createretrievablehint( "trophy_system", &"MP_TROPHY_SYSTEM_PICKUP" ); + createretrievablehint( "acoustic_sensor", &"MP_ACOUSTIC_SENSOR_PICKUP" ); + createretrievablehint( "camera_spike", &"MP_CAMERA_SPIKE_PICKUP" ); + createretrievablehint( "satchel_charge", &"MP_SATCHEL_CHARGE_PICKUP" ); + createretrievablehint( "scrambler", &"MP_SCRAMBLER_PICKUP" ); + createdestroyhint( "trophy_system", &"MP_TROPHY_SYSTEM_DESTROY" ); + createdestroyhint( "sensor_grenade", &"MP_SENSOR_GRENADE_DESTROY" ); + createhackerhint( "claymore_mp", &"MP_CLAYMORE_HACKING" ); + createhackerhint( "bouncingbetty_mp", &"MP_BOUNCINGBETTY_HACKING" ); + createhackerhint( "trophy_system_mp", &"MP_TROPHY_SYSTEM_HACKING" ); + createhackerhint( "acoustic_sensor_mp", &"MP_ACOUSTIC_SENSOR_HACKING" ); + createhackerhint( "camera_spike_mp", &"MP_CAMERA_SPIKE_HACKING" ); + createhackerhint( "satchel_charge_mp", &"MP_SATCHEL_CHARGE_HACKING" ); + createhackerhint( "scrambler_mp", &"MP_SCRAMBLER_HACKING" ); +} + +onplayerconnect() +{ + if ( isDefined( level._weaponobjects_on_player_connect_override ) ) + { + level thread [[ level._weaponobjects_on_player_connect_override ]](); + return; + } + for ( ;; ) + { + level waittill( "connecting", player ); + player.usedweapons = 0; + player.hits = 0; + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + pixbeginevent( "onPlayerSpawned" ); + if ( !isDefined( self.watchersinitialized ) ) + { + self createbasewatchers(); + self setupretrievablewatcher(); + self thread watchweaponobjectusage(); + self.watchersinitialized = 1; + } + self resetwatchers(); + pixendevent(); + } +} + +resetwatchers() +{ + if ( !isDefined( self.weaponobjectwatcherarray ) ) + { + return undefined; + } + team = self.team; + _a199 = self.weaponobjectwatcherarray; + _k199 = getFirstArrayKey( _a199 ); + while ( isDefined( _k199 ) ) + { + watcher = _a199[ _k199 ]; + resetweaponobjectwatcher( watcher, team ); + _k199 = getNextArrayKey( _a199, _k199 ); + } +} + +createbasewatchers() +{ + _a208 = level.watcherweapons; + index = getFirstArrayKey( _a208 ); + while ( isDefined( index ) ) + { + weapon = _a208[ index ]; + self createweaponobjectwatcher( level.watcherweaponnames[ index ], weapon, self.team ); + index = getNextArrayKey( _a208, index ); + } + _a214 = level.retrievableweapons; + index = getFirstArrayKey( _a214 ); + while ( isDefined( index ) ) + { + weapon = _a214[ index ]; + self createweaponobjectwatcher( level.retrievableweaponnames[ index ], weapon, self.team ); + index = getNextArrayKey( _a214, index ); + } +} + +setupretrievablewatcher() +{ + i = 0; + while ( i < level.retrievableweapons.size ) + { + watcher = getweaponobjectwatcherbyweapon( level.retrievableweapons[ i ] ); + if ( !isDefined( watcher.onspawnretrievetriggers ) ) + { + watcher.onspawnretrievetriggers = ::onspawnretrievableweaponobject; + } + if ( !isDefined( watcher.ondestroyed ) ) + { + watcher.ondestroyed = ::ondestroyed; + } + if ( !isDefined( watcher.pickup ) ) + { + watcher.pickup = ::pickup; + } + i++; + } +} + +createballisticknifewatcher() +{ + watcher = self createuseweaponobjectwatcher( "knife_ballistic", "knife_ballistic_mp", self.team ); + watcher.onspawn = ::maps/mp/_ballistic_knife::onspawn; + watcher.detonate = ::deleteent; + watcher.onspawnretrievetriggers = ::maps/mp/_ballistic_knife::onspawnretrievetrigger; + watcher.storedifferentobject = 1; +} + +createhatchetwatcher() +{ + watcher = self createuseweaponobjectwatcher( "hatchet", "hatchet_mp", self.team ); + watcher.detonate = ::deleteent; + watcher.onspawn = ::voidonspawn; + watcher.onspawnretrievetriggers = ::onspawnhatchettrigger; +} + +createtactinsertwatcher() +{ + watcher = self createuseweaponobjectwatcher( "tactical_insertion", "tactical_insertion_mp", self.team ); + watcher.playdestroyeddialog = 0; +} + +creatercbombwatcher() +{ +} + +createqrdronewatcher() +{ +} + +createplayerhelicopterwatcher() +{ + watcher = self createuseweaponobjectwatcher( "helicopter_player", "helicopter_player_mp", self.team ); + watcher.altdetonate = 1; + watcher.headicon = 0; +} + +createclaymorewatcher() +{ + watcher = self createproximityweaponobjectwatcher( "claymore", "claymore_mp", self.team ); + watcher.watchforfire = 1; + watcher.detonate = ::claymoredetonate; + watcher.activatesound = "wpn_claymore_alert"; + watcher.hackable = 1; + watcher.hackertoolradius = level.claymorehackertoolradius; + watcher.hackertooltimems = level.claymorehackertooltimems; + watcher.reconmodel = "t6_wpn_claymore_world_detect"; + watcher.ownergetsassist = 1; + detectionconeangle = weapons_get_dvar_int( "scr_weaponobject_coneangle" ); + watcher.detectiondot = cos( detectionconeangle ); + watcher.detectionmindist = weapons_get_dvar_int( "scr_weaponobject_mindist" ); + watcher.detectiongraceperiod = weapons_get_dvar( "scr_weaponobject_graceperiod" ); + watcher.detonateradius = weapons_get_dvar_int( "scr_weaponobject_radius" ); + watcher.stun = ::weaponstun; + watcher.stuntime = 5; +} + +waittillnotmoving_and_notstunned() +{ + prevorigin = self.origin; + while ( 1 ) + { + wait 0,15; + if ( self.origin == prevorigin && !self isstunned() ) + { + return; + } + else + { + prevorigin = self.origin; + } + } +} + +voidonspawn( unused0, unused1 ) +{ +} + +deleteent( attacker, emp ) +{ + self delete(); +} + +clearfxondeath( fx ) +{ + fx endon( "death" ); + self waittill_any( "death", "hacked" ); + fx delete(); +} + +deleteweaponobjectarray() +{ + while ( isDefined( self.objectarray ) ) + { + i = 0; + while ( i < self.objectarray.size ) + { + if ( isDefined( self.objectarray[ i ] ) ) + { + self.objectarray[ i ] delete(); + } + i++; + } + } + self.objectarray = []; +} + +claymoredetonate( attacker, weaponname ) +{ + from_emp = 0; + if ( !isDefined( from_emp ) || !from_emp ) + { + if ( isDefined( attacker ) ) + { + if ( level.teambased || attacker.team != self.owner.team && attacker != self.owner ) + { + attacker maps/mp/_challenges::destroyedexplosive(); + } + } + } + maps/mp/gametypes_zm/_weaponobjects::weapondetonate( attacker, weaponname ); +} + +weapondetonate( attacker, weaponname ) +{ + from_emp = 0; + if ( from_emp ) + { + self delete(); + return; + } + if ( isDefined( attacker ) ) + { + self detonate( attacker ); + } + else if ( isDefined( self.owner ) && isplayer( self.owner ) ) + { + self detonate( self.owner ); + } + else + { + self detonate(); + } +} + +waitanddetonate( object, delay, attacker, weaponname ) +{ + object endon( "death" ); + object endon( "hacked" ); + from_emp = 0; + if ( from_emp ) + { + object setclientflag( 15 ); + object setclientflag( 9 ); + object.stun_fx = 1; + if ( isDefined( object.name ) && object.name == "qrdrone_turret_mp" ) + { + playfx( level._equipment_emp_destroy_fx, object.origin + ( 0, 0, 1 ), ( 0, randomfloat( 360 ), 0 ) ); + } + else + { + playfx( level._equipment_emp_destroy_fx, object.origin + vectorScale( ( 0, 0, 1 ), 5 ), ( 0, randomfloat( 360 ), 0 ) ); + } + delay = 1,1; + } + if ( delay ) + { + wait delay; + } + if ( isDefined( object.detonated ) && object.detonated == 1 ) + { + return; + } + if ( !isDefined( self.detonate ) ) + { + return; + } + if ( isDefined( attacker ) && isplayer( attacker ) && isDefined( attacker.pers[ "team" ] ) && isDefined( object.owner ) && isDefined( object.owner.pers[ "team" ] ) ) + { + if ( level.teambased ) + { + if ( attacker.pers[ "team" ] != object.owner.pers[ "team" ] ) + { + attacker notify( "destroyed_explosive" ); + } + } + else + { + if ( attacker != object.owner ) + { + attacker notify( "destroyed_explosive" ); + } + } + } + object.detonated = 1; + object [[ self.detonate ]]( attacker, weaponname ); +} + +detonateweaponobjectarray( forcedetonation, weapon ) +{ + undetonated = []; + while ( isDefined( self.objectarray ) ) + { + i = 0; + while ( i < self.objectarray.size ) + { + if ( isDefined( self.objectarray[ i ] ) ) + { + if ( self.objectarray[ i ] isstunned() && forcedetonation == 0 ) + { + undetonated[ undetonated.size ] = self.objectarray[ i ]; + i++; + continue; + } + else + { + if ( isDefined( weapon ) ) + { + if ( weapon ishacked() && weapon.name != self.objectarray[ i ].name ) + { + undetonated[ undetonated.size ] = self.objectarray[ i ]; + i++; + continue; + } + else if ( self.objectarray[ i ] ishacked() && weapon.name != self.objectarray[ i ].name ) + { + undetonated[ undetonated.size ] = self.objectarray[ i ]; + i++; + continue; + } + } + else + { + self thread waitanddetonate( self.objectarray[ i ], 0,1, undefined, weapon ); + } + } + } + i++; + } + } + self.objectarray = undetonated; +} + +addweaponobjecttowatcher( watchername, weapon ) +{ + watcher = getweaponobjectwatcher( watchername ); +/# + assert( isDefined( watcher ), "Weapon object watcher " + watchername + " does not exist" ); +#/ + self addweaponobject( watcher, weapon ); +} + +addweaponobject( watcher, weapon ) +{ + if ( !isDefined( watcher.storedifferentobject ) ) + { + watcher.objectarray[ watcher.objectarray.size ] = weapon; + } + weapon.owner = self; + weapon.detonated = 0; + weapon.name = watcher.weapon; + if ( isDefined( watcher.ondamage ) ) + { + weapon thread [[ watcher.ondamage ]]( watcher ); + } + else + { + weapon thread weaponobjectdamage( watcher ); + } + weapon.ownergetsassist = watcher.ownergetsassist; + if ( isDefined( watcher.onspawn ) ) + { + weapon thread [[ watcher.onspawn ]]( watcher, self ); + } + if ( isDefined( watcher.onspawnfx ) ) + { + weapon thread [[ watcher.onspawnfx ]](); + } + if ( isDefined( watcher.reconmodel ) ) + { + weapon thread attachreconmodel( watcher.reconmodel, self ); + } + if ( isDefined( watcher.onspawnretrievetriggers ) ) + { + weapon thread [[ watcher.onspawnretrievetriggers ]]( watcher, self ); + } + if ( watcher.hackable ) + { + weapon thread hackerinit( watcher ); + } + if ( isDefined( watcher.stun ) ) + { + weapon thread watchscramble( watcher ); + } + if ( watcher.playdestroyeddialog ) + { + weapon thread playdialogondeath( self ); + weapon thread watchobjectdamage( self ); + } + if ( watcher.deleteonkillbrush ) + { + weapon thread deleteonkillbrush( self ); + } +} + +watchscramble( watcher ) +{ +} + +deleteweaponobjecthelper( weapon_ent ) +{ + if ( !isDefined( weapon_ent.name ) ) + { + return; + } + watcher = self getweaponobjectwatcherbyweapon( weapon_ent.name ); + if ( !isDefined( watcher ) ) + { + return; + } + watcher.objectarray = deleteweaponobject( watcher, weapon_ent ); +} + +deleteweaponobject( watcher, weapon_ent ) +{ + temp_objectarray = watcher.objectarray; + watcher.objectarray = []; + j = 0; + i = 0; + while ( i < temp_objectarray.size ) + { + if ( !isDefined( temp_objectarray[ i ] ) || temp_objectarray[ i ] == weapon_ent ) + { + i++; + continue; + } + else + { + watcher.objectarray[ j ] = temp_objectarray[ i ]; + j++; + } + i++; + } + return watcher.objectarray; +} + +weaponobjectdamage( watcher ) +{ + self endon( "death" ); + self endon( "hacked" ); + self setcandamage( 1 ); + self.maxhealth = 100000; + self.health = self.maxhealth; + attacker = undefined; + for ( ;; ) + { + while ( 1 ) + { + self waittill( "damage", damage, attacker, direction_vec, point, type, modelname, tagname, partname, weaponname, idflags ); + if ( isDefined( weaponname ) ) + { + switch( weaponname ) + { + case "concussion_grenade_mp": + case "flash_grenade_mp": + case "proximity_grenade_mp": + if ( watcher.stuntime > 0 ) + { + self thread stunstart( watcher, watcher.stuntime ); + } + if ( level.teambased && self.owner.team != attacker.team ) + { + if ( maps/mp/gametypes_zm/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes_zm/_damagefeedback::updatedamagefeedback(); + } + continue; + } + else + { + if ( !level.teambased && self.owner != attacker ) + { + if ( maps/mp/gametypes_zm/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes_zm/_damagefeedback::updatedamagefeedback(); + } + } + } + } + case "willy_pete_mp": + } + case "emp_grenade_mp": + if ( level.teambased && self.owner.team != attacker.team ) + { + if ( maps/mp/gametypes_zm/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes_zm/_damagefeedback::updatedamagefeedback(); + } + } + else if ( !level.teambased && self.owner != attacker ) + { + if ( maps/mp/gametypes_zm/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes_zm/_damagefeedback::updatedamagefeedback(); + } + } + break; + break; + default: + } + } + if ( !isplayer( attacker ) && isDefined( attacker.owner ) ) + { + attacker = attacker.owner; + } + while ( level.teambased && isplayer( attacker ) ) + { + while ( !level.hardcoremode && self.owner.team == attacker.pers[ "team" ] && self.owner != attacker ) + { + continue; + } + } + if ( maps/mp/gametypes_zm/_globallogic_player::dodamagefeedback( weaponname, attacker ) ) + { + attacker maps/mp/gametypes_zm/_damagefeedback::updatedamagefeedback(); + } + if ( !isvehicle( self ) && !friendlyfirecheck( self.owner, attacker ) ) + { + continue; + } + } + if ( level.weaponobjectexplodethisframe ) + { + wait ( 0,1 + randomfloat( 0,4 ) ); + } + else wait 0,05; + if ( !isDefined( self ) ) + { + return; + } + level.weaponobjectexplodethisframe = 1; + thread resetweaponobjectexplodethisframe(); + if ( isDefined( type ) && !issubstr( type, "MOD_GRENADE_SPLASH" ) || issubstr( type, "MOD_GRENADE" ) && issubstr( type, "MOD_EXPLOSIVE" ) ) + { + self.waschained = 1; + } + if ( isDefined( idflags ) && idflags & level.idflags_penetration ) + { + self.wasdamagedfrombulletpenetration = 1; + } + self.wasdamaged = 1; + watcher thread waitanddetonate( self, 0, attacker, weaponname ); + } + } +} + +playdialogondeath( owner ) +{ + owner endon( "death" ); + owner endon( "disconnect" ); + self endon( "hacked" ); + self waittill( "death" ); + if ( isDefined( self.playdialog ) && self.playdialog ) + { + owner maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "equipment_destroyed", "item_destroyed" ); + } +} + +watchobjectdamage( owner ) +{ + owner endon( "death" ); + owner endon( "disconnect" ); + self endon( "hacked" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "damage", damage, attacker ); + if ( isDefined( attacker ) && isplayer( attacker ) && attacker != owner ) + { + self.playdialog = 1; + continue; + } + else + { + self.playdialog = 0; + } + } +} + +stunstart( watcher, time ) +{ + self endon( "death" ); + if ( self isstunned() ) + { + return; + } + if ( isDefined( self.camerahead ) ) + { + self.camerahead setclientflag( 9 ); + } + self setclientflag( 9 ); + if ( isDefined( watcher.stun ) ) + { + self thread [[ watcher.stun ]](); + } + if ( watcher.name == "rcbomb" ) + { + self.owner freezecontrolswrapper( 1 ); + } + if ( isDefined( time ) ) + { + wait time; + } + else + { + return; + } + if ( watcher.name == "rcbomb" ) + { + self.owner freezecontrolswrapper( 0 ); + } + self stunstop(); +} + +stunstop() +{ + self notify( "not_stunned" ); + if ( isDefined( self.camerahead ) ) + { + self.camerahead clearclientflag( 9 ); + } + self clearclientflag( 9 ); +} + +weaponstun() +{ + self endon( "death" ); + self endon( "not_stunned" ); + origin = self gettagorigin( "tag_fx" ); + if ( !isDefined( origin ) ) + { + origin = self.origin + vectorScale( ( 0, 0, 1 ), 10 ); + } + self.stun_fx = spawn( "script_model", origin ); + self.stun_fx setmodel( "tag_origin" ); + self thread stunfxthink( self.stun_fx ); + wait 0,1; + playfxontag( level._equipment_spark_fx, self.stun_fx, "tag_origin" ); + self.stun_fx playsound( "dst_disable_spark" ); +} + +stunfxthink( fx ) +{ + fx endon( "death" ); + self waittill_any( "death", "not_stunned" ); + fx delete(); +} + +isstunned() +{ + return isDefined( self.stun_fx ); +} + +resetweaponobjectexplodethisframe() +{ + wait 0,05; + level.weaponobjectexplodethisframe = 0; +} + +getweaponobjectwatcher( name ) +{ + if ( !isDefined( self.weaponobjectwatcherarray ) ) + { + return undefined; + } + watcher = 0; + while ( watcher < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ watcher ].name == name ) + { + return self.weaponobjectwatcherarray[ watcher ]; + } + watcher++; + } + return undefined; +} + +getweaponobjectwatcherbyweapon( weapon ) +{ + if ( !isDefined( self.weaponobjectwatcherarray ) ) + { + return undefined; + } + watcher = 0; + while ( watcher < self.weaponobjectwatcherarray.size ) + { + if ( isDefined( self.weaponobjectwatcherarray[ watcher ].weapon ) && self.weaponobjectwatcherarray[ watcher ].weapon == weapon ) + { + return self.weaponobjectwatcherarray[ watcher ]; + } + if ( isDefined( self.weaponobjectwatcherarray[ watcher ].weapon ) && isDefined( self.weaponobjectwatcherarray[ watcher ].altweapon ) && self.weaponobjectwatcherarray[ watcher ].altweapon == weapon ) + { + return self.weaponobjectwatcherarray[ watcher ]; + } + watcher++; + } + return undefined; +} + +resetweaponobjectwatcher( watcher, ownerteam ) +{ + if ( level.deleteexplosivesonspawn == 1 ) + { + self notify( "weapon_object_destroyed" ); + watcher deleteweaponobjectarray(); + } + watcher.ownerteam = ownerteam; +} + +createweaponobjectwatcher( name, weapon, ownerteam ) +{ + if ( !isDefined( self.weaponobjectwatcherarray ) ) + { + self.weaponobjectwatcherarray = []; + } + weaponobjectwatcher = getweaponobjectwatcher( name ); + if ( !isDefined( weaponobjectwatcher ) ) + { + weaponobjectwatcher = spawnstruct(); + self.weaponobjectwatcherarray[ self.weaponobjectwatcherarray.size ] = weaponobjectwatcher; + weaponobjectwatcher.name = name; + weaponobjectwatcher.type = "use"; + weaponobjectwatcher.weapon = weapon; + weaponobjectwatcher.weaponidx = getweaponindexfromname( weapon ); + weaponobjectwatcher.watchforfire = 0; + weaponobjectwatcher.hackable = 0; + weaponobjectwatcher.altdetonate = 0; + weaponobjectwatcher.detectable = 1; + weaponobjectwatcher.headicon = 1; + weaponobjectwatcher.stuntime = 0; + weaponobjectwatcher.activatesound = undefined; + weaponobjectwatcher.ignoredirection = undefined; + weaponobjectwatcher.immediatedetonation = undefined; + weaponobjectwatcher.deploysound = getweaponfiresound( weaponobjectwatcher.weaponidx ); + weaponobjectwatcher.deploysoundplayer = getweaponfiresoundplayer( weaponobjectwatcher.weaponidx ); + weaponobjectwatcher.pickupsound = getweaponpickupsound( weaponobjectwatcher.weaponidx ); + weaponobjectwatcher.pickupsoundplayer = getweaponpickupsoundplayer( weaponobjectwatcher.weaponidx ); + weaponobjectwatcher.altweapon = undefined; + weaponobjectwatcher.ownergetsassist = 0; + weaponobjectwatcher.playdestroyeddialog = 1; + weaponobjectwatcher.deleteonkillbrush = 1; + weaponobjectwatcher.deleteondifferentobjectspawn = 1; + weaponobjectwatcher.enemydestroy = 0; + weaponobjectwatcher.onspawn = undefined; + weaponobjectwatcher.onspawnfx = undefined; + weaponobjectwatcher.onspawnretrievetriggers = undefined; + weaponobjectwatcher.ondetonated = undefined; + weaponobjectwatcher.detonate = undefined; + weaponobjectwatcher.stun = undefined; + weaponobjectwatcher.ondestroyed = undefined; + if ( !isDefined( weaponobjectwatcher.objectarray ) ) + { + weaponobjectwatcher.objectarray = []; + } + } + resetweaponobjectwatcher( weaponobjectwatcher, ownerteam ); + return weaponobjectwatcher; +} + +createuseweaponobjectwatcher( name, weapon, ownerteam ) +{ + weaponobjectwatcher = createweaponobjectwatcher( name, weapon, ownerteam ); + weaponobjectwatcher.type = "use"; + weaponobjectwatcher.onspawn = ::onspawnuseweaponobject; + return weaponobjectwatcher; +} + +createproximityweaponobjectwatcher( name, weapon, ownerteam ) +{ + weaponobjectwatcher = createweaponobjectwatcher( name, weapon, ownerteam ); + weaponobjectwatcher.type = "proximity"; + weaponobjectwatcher.onspawn = ::onspawnproximityweaponobject; + detectionconeangle = weapons_get_dvar_int( "scr_weaponobject_coneangle" ); + weaponobjectwatcher.detectiondot = cos( detectionconeangle ); + weaponobjectwatcher.detectionmindist = weapons_get_dvar_int( "scr_weaponobject_mindist" ); + weaponobjectwatcher.detectiongraceperiod = weapons_get_dvar( "scr_weaponobject_graceperiod" ); + weaponobjectwatcher.detonateradius = weapons_get_dvar_int( "scr_weaponobject_radius" ); + return weaponobjectwatcher; +} + +commononspawnuseweaponobject( watcher, owner ) +{ + if ( watcher.detectable ) + { + if ( isDefined( watcher.ismovable ) && watcher.ismovable ) + { + self thread weaponobjectdetectionmovable( owner.pers[ "team" ] ); + } + else + { + self thread weaponobjectdetectiontrigger_wait( owner.pers[ "team" ] ); + } + if ( watcher.headicon && level.teambased ) + { + self waittillnotmoving(); + offset = level.weaponobjects_headicon_offset[ "default" ]; + if ( isDefined( level.weaponobjects_headicon_offset[ self.name ] ) ) + { + offset = level.weaponobjects_headicon_offset[ self.name ]; + } + } + } +} + +onspawnuseweaponobject( watcher, owner ) +{ + self commononspawnuseweaponobject( watcher, owner ); +} + +onspawnproximityweaponobject( watcher, owner ) +{ + self thread commononspawnuseweaponobject( watcher, owner ); + self thread proximityweaponobjectdetonation( watcher ); +/# + if ( getDvarInt( #"38868733" ) ) + { + self thread proximityweaponobjectdebug( watcher ); +#/ + } +} + +watchweaponobjectusage() +{ + self endon( "disconnect" ); + if ( !isDefined( self.weaponobjectwatcherarray ) ) + { + self.weaponobjectwatcherarray = []; + } + self thread watchweaponobjectspawn(); + self thread watchweaponprojectileobjectspawn(); + self thread watchweaponobjectdetonation(); + self thread watchweaponobjectaltdetonation(); + self thread watchweaponobjectaltdetonate(); + self thread deleteweaponobjectson(); +} + +watchweaponobjectspawn() +{ + self notify( "watchWeaponObjectSpawn" ); + self endon( "watchWeaponObjectSpawn" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "grenade_fire", weapon, weapname ); + switch( weapname ) + { + case "acoustic_sensor_mp": + case "bouncingbetty_mp": + case "camera_spike_mp": + case "scrambler_mp": + case "tactical_insertion_mp": + break; + case "bouncingbetty_mp": + case "claymore_mp": + case "proximity_grenade_mp": + case "satchel_charge_mp": + case "sensor_grenade_mp": + case "trophy_system_mp": + i = 0; + while ( i < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ i ].weapon != weapname ) + { + i++; + continue; + } + else + { + objectarray_size = self.weaponobjectwatcherarray[ i ].objectarray.size; + j = 0; + while ( j < objectarray_size ) + { + if ( !isDefined( self.weaponobjectwatcherarray[ i ].objectarray[ j ] ) ) + { + self.weaponobjectwatcherarray[ i ].objectarray = deleteweaponobject( self.weaponobjectwatcherarray[ i ], weapon ); + } + j++; + } + numallowed = 2; + if ( weapname == "proximity_grenade_mp" ) + { + numallowed = weapons_get_dvar_int( "scr_proximityGrenadeMaxInstances" ); + } + if ( isDefined( self.weaponobjectwatcherarray[ i ].detonate ) && self.weaponobjectwatcherarray[ i ].objectarray.size > ( numallowed - 1 ) ) + { + self.weaponobjectwatcherarray[ i ] thread waitanddetonate( self.weaponobjectwatcherarray[ i ].objectarray[ 0 ], 0,1, undefined, weapname ); + } + } + i++; + } + default: + } + if ( !self ishacked() ) + { + if ( weapname != "claymore_mp" || weapname == "satchel_charge_mp" && weapname == "bouncingbetty_mp" ) + { + self addweaponstat( weapname, "used", 1 ); + } + } + watcher = getweaponobjectwatcherbyweapon( weapname ); + if ( isDefined( watcher ) ) + { + self addweaponobject( watcher, weapon ); + } + } + } + } +} + +watchweaponprojectileobjectspawn() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "missile_fire", weapon, weapname ); + watcher = getweaponobjectwatcherbyweapon( weapname ); + if ( isDefined( watcher ) ) + { + self addweaponobject( watcher, weapon ); + objectarray_size = watcher.objectarray.size; + j = 0; + while ( j < objectarray_size ) + { + if ( !isDefined( watcher.objectarray[ j ] ) ) + { + watcher.objectarray = deleteweaponobject( watcher, weapon ); + } + j++; + } + if ( isDefined( watcher.detonate ) && watcher.objectarray.size > 1 ) + { + watcher thread waitanddetonate( watcher.objectarray[ 0 ], 0,1 ); + } + } + } +} + +proximityweaponobjectdebug( watcher ) +{ +/# + self waittillnotmoving(); + self thread showcone( acos( watcher.detectiondot ), watcher.detonateradius, ( 1, 0,85, 0 ) ); + self thread showcone( 60, 256, ( 0, 0, 1 ) ); +#/ +} + +vectorcross( v1, v2 ) +{ +/# + return ( ( v1[ 1 ] * v2[ 2 ] ) - ( v1[ 2 ] * v2[ 1 ] ), ( v1[ 2 ] * v2[ 0 ] ) - ( v1[ 0 ] * v2[ 2 ] ), ( v1[ 0 ] * v2[ 1 ] ) - ( v1[ 1 ] * v2[ 0 ] ) ); +#/ +} + +showcone( angle, range, color ) +{ +/# + self endon( "death" ); + start = self.origin; + forward = anglesToForward( self.angles ); + right = vectorcross( forward, ( 0, 0, 1 ) ); + up = vectorcross( forward, right ); + fullforward = forward * range * cos( angle ); + sideamnt = range * sin( angle ); + while ( 1 ) + { + prevpoint = ( 0, 0, 1 ); + i = 0; + while ( i <= 20 ) + { + coneangle = ( i / 20 ) * 360; + point = ( start + fullforward ) + ( sideamnt * ( ( right * cos( coneangle ) ) + ( up * sin( coneangle ) ) ) ); + if ( i > 0 ) + { + line( start, point, color ); + line( prevpoint, point, color ); + } + prevpoint = point; + i++; + } + wait 0,05; +#/ + } +} + +weaponobjectdetectionmovable( ownerteam ) +{ + self endon( "end_detection" ); + level endon( "game_ended" ); + self endon( "death" ); + self endon( "hacked" ); + if ( level.oldschool ) + { + return; + } + if ( !level.teambased ) + { + return; + } + self.detectid = "rcBomb" + getTime() + randomint( 1000000 ); + while ( !level.gameended ) + { + wait 1; + players = get_players(); + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( isai( player ) ) + { + i++; + continue; + } + else if ( isDefined( self.model_name ) && player hasperk( "specialty_detectexplosive" ) ) + { + switch( self.model_name ) + { + case "t6_wpn_c4_world_detect": + case "t6_wpn_claymore_world_detect": + break; + default: + } + } + else if ( player.team == ownerteam ) + { + i++; + continue; + } + else if ( isDefined( player.bombsquadids[ self.detectid ] ) ) + { + i++; + continue; + } + i++; + } + } + } +} + +seticonpos( item, icon, heightincrease ) +{ + icon.x = item.origin[ 0 ]; + icon.y = item.origin[ 1 ]; + icon.z = item.origin[ 2 ] + heightincrease; +} + +weaponobjectdetectiontrigger_wait( ownerteam ) +{ + self endon( "death" ); + self endon( "hacked" ); + waittillnotmoving(); + if ( level.oldschool ) + { + return; + } + self thread weaponobjectdetectiontrigger( ownerteam ); +} + +weaponobjectdetectiontrigger( ownerteam ) +{ + trigger = spawn( "trigger_radius", self.origin - vectorScale( ( 0, 0, 1 ), 128 ), 0, 512, 256 ); + trigger.detectid = "trigger" + getTime() + randomint( 1000000 ); + trigger sethintlowpriority( 1 ); + self waittill_any( "death", "hacked" ); + trigger notify( "end_detection" ); + if ( isDefined( trigger.bombsquadicon ) ) + { + trigger.bombsquadicon destroy(); + } + trigger delete(); +} + +hackertriggersetvisibility( owner ) +{ + self endon( "death" ); +/# + assert( isplayer( owner ) ); +#/ + ownerteam = owner.pers[ "team" ]; + for ( ;; ) + { + if ( level.teambased ) + { + self setvisibletoallexceptteam( ownerteam ); + self setexcludeteamfortrigger( ownerteam ); + } + else + { + self setvisibletoall(); + self setteamfortrigger( "none" ); + } + self setinvisibletoplayer( owner ); + level waittill_any( "player_spawned", "joined_team" ); + } +} + +hackernotmoving() +{ + self endon( "death" ); + self waittillnotmoving(); + self notify( "landed" ); +} + +hackerinit( watcher ) +{ + self thread hackernotmoving(); + event = self waittill_any_return( "death", "landed" ); + if ( event == "death" ) + { + return; + } + triggerorigin = self.origin; + if ( isDefined( self.name ) && self.name == "satchel_charge_mp" ) + { + triggerorigin = self gettagorigin( "tag_fx" ); + } + self.hackertrigger = spawn( "trigger_radius_use", triggerorigin, level.weaponobjects_hacker_trigger_width, level.weaponobjects_hacker_trigger_height ); +/# +#/ + self.hackertrigger sethintlowpriority( 1 ); + self.hackertrigger setcursorhint( "HINT_NOICON", self ); + self.hackertrigger setignoreentfortrigger( self ); + self.hackertrigger enablelinkto(); + self.hackertrigger linkto( self ); + if ( isDefined( level.hackerhints[ self.name ] ) ) + { + self.hackertrigger sethintstring( level.hackerhints[ self.name ].hint ); + } + else + { + self.hackertrigger sethintstring( &"MP_GENERIC_HACKING" ); + } + self.hackertrigger setperkfortrigger( "specialty_disarmexplosive" ); + self.hackertrigger thread hackertriggersetvisibility( self.owner ); + self thread hackerthink( self.hackertrigger, watcher ); +} + +hackerthink( trigger, watcher ) +{ + self endon( "death" ); + for ( ;; ) + { + trigger waittill( "trigger", player, instant ); + if ( !isDefined( instant ) && !trigger hackerresult( player, self.owner ) ) + { + continue; + } + else + { + self.owner hackerremoveweapon( self ); + self.owner maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "hacked_equip", "item_destroyed" ); + self.hacked = 1; + self setmissileowner( player ); + self setteam( player.pers[ "team" ] ); + self.owner = player; + if ( isweaponequipment( self.name ) ) + { + } + if ( self.name == "satchel_charge_mp" && isDefined( player.lowermessage ) ) + { + player.lowermessage settext( &"PLATFORM_SATCHEL_CHARGE_DOUBLE_TAP" ); + player.lowermessage.alpha = 1; + player.lowermessage fadeovertime( 2 ); + player.lowermessage.alpha = 0; + } + self notify( "hacked" ); + level notify( "hacked" ); + if ( self.name == "camera_spike_mp" && isDefined( self.camerahead ) ) + { + self.camerahead notify( "hacked" ); + } +/# +#/ + if ( isDefined( watcher.stun ) ) + { + self thread stunstart( watcher, 0,75 ); + wait 0,75; + } + else + { + wait 0,05; + } + if ( isDefined( player ) && player.sessionstate == "playing" ) + { + player notify( "grenade_fire" ); + } + else + { + watcher thread waitanddetonate( self, 0 ); + } + return; + } + } +} + +ishacked() +{ + if ( isDefined( self.hacked ) ) + { + return self.hacked; + } +} + +hackerunfreezeplayer( player ) +{ + self endon( "hack_done" ); + self waittill( "death" ); + if ( isDefined( player ) ) + { + player freeze_player_controls( 0 ); + player enableweapons(); + } +} + +hackerresult( player, owner ) +{ + success = 1; + time = getTime(); + hacktime = getDvarFloat( "perk_disarmExplosiveTime" ); + if ( !canhack( player, owner, 1 ) ) + { + return 0; + } + self thread hackerunfreezeplayer( player ); + while ( ( time + ( hacktime * 1000 ) ) > getTime() ) + { + if ( !canhack( player, owner, 0 ) ) + { + success = 0; + break; + } + else if ( !player usebuttonpressed() ) + { + success = 0; + break; + } + else if ( !isDefined( self ) ) + { + success = 0; + break; + } + else + { + player freeze_player_controls( 1 ); + player disableweapons(); + if ( !isDefined( self.progressbar ) ) + { + self.progressbar = player createprimaryprogressbar(); + self.progressbar.lastuserate = -1; + self.progressbar showelem(); + self.progressbar updatebar( 0,01, 1 / hacktime ); + self.progresstext = player createprimaryprogressbartext(); + self.progresstext settext( &"MP_HACKING" ); + self.progresstext showelem(); + player playlocalsound( "evt_hacker_hacking" ); + } + wait 0,05; + } + } + if ( isDefined( player ) ) + { + player freeze_player_controls( 0 ); + player enableweapons(); + } + if ( isDefined( self.progressbar ) ) + { + self.progressbar destroyelem(); + self.progresstext destroyelem(); + } + if ( isDefined( self ) ) + { + self notify( "hack_done" ); + } + return success; +} + +canhack( player, owner, weapon_check ) +{ + if ( !isDefined( player ) ) + { + return 0; + } + if ( !isplayer( player ) ) + { + return 0; + } + if ( !isalive( player ) ) + { + return 0; + } + if ( !isDefined( owner ) ) + { + return 0; + } + if ( owner == player ) + { + return 0; + } + if ( level.teambased && player.team == owner.team ) + { + return 0; + } + if ( isDefined( player.isdefusing ) && player.isdefusing ) + { + return 0; + } + if ( isDefined( player.isplanting ) && player.isplanting ) + { + return 0; + } + if ( isDefined( player.proxbar ) && !player.proxbar.hidden ) + { + return 0; + } + if ( isDefined( player.revivingteammate ) && player.revivingteammate == 1 ) + { + return 0; + } + if ( !player isonground() ) + { + return 0; + } + if ( player isinvehicle() ) + { + return 0; + } + if ( player isweaponviewonlylinked() ) + { + return 0; + } + if ( !player hasperk( "specialty_disarmexplosive" ) ) + { + return 0; + } + if ( player isempjammed() ) + { + return 0; + } + if ( isDefined( player.laststand ) && player.laststand ) + { + return 0; + } + if ( weapon_check ) + { + if ( player isthrowinggrenade() ) + { + return 0; + } + if ( player isswitchingweapons() ) + { + return 0; + } + if ( player ismeleeing() ) + { + return 0; + } + weapon = player getcurrentweapon(); + if ( !isDefined( weapon ) ) + { + return 0; + } + if ( weapon == "none" ) + { + return 0; + } + if ( isweaponequipment( weapon ) && player isfiring() ) + { + return 0; + } + if ( isweaponspecificuse( weapon ) ) + { + return 0; + } + } + return 1; +} + +hackerremoveweapon( weapon ) +{ + i = 0; + while ( i < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ i ].weapon != weapon.name ) + { + i++; + continue; + } + else + { + objectarray_size = self.weaponobjectwatcherarray[ i ].objectarray.size; + j = 0; + while ( j < objectarray_size ) + { + self.weaponobjectwatcherarray[ i ].objectarray = deleteweaponobject( self.weaponobjectwatcherarray[ i ], weapon ); + j++; + } + return; + } + i++; + } +} + +proximityweaponobjectdetonation( watcher ) +{ + self endon( "death" ); + self endon( "hacked" ); + self waittillnotmoving(); + if ( isDefined( watcher.activationdelay ) ) + { + wait watcher.activationdelay; + } + damagearea = spawn( "trigger_radius", self.origin + ( 0, 0, 0 - watcher.detonateradius ), level.aitriggerspawnflags | level.vehicletriggerspawnflags, watcher.detonateradius, watcher.detonateradius * 2 ); + damagearea enablelinkto(); + damagearea linkto( self ); + self thread deleteondeath( damagearea ); + up = anglesToUp( self.angles ); + traceorigin = self.origin + up; + while ( 1 ) + { + damagearea waittill( "trigger", ent ); + while ( getDvarInt( #"38868733" ) != 1 ) + { + if ( isDefined( self.owner ) && ent == self.owner ) + { + continue; + } + while ( isDefined( self.owner ) && isvehicle( ent ) && isDefined( ent.owner ) && self.owner == ent.owner ) + { + continue; + } + while ( !friendlyfirecheck( self.owner, ent, 0 ) ) + { + continue; + } + } + if ( lengthsquared( ent getvelocity() ) < 10 && !isDefined( watcher.immediatedetonation ) ) + { + continue; + } + while ( !ent shouldaffectweaponobject( self, watcher ) ) + { + continue; + } + while ( self isstunned() ) + { + continue; + } + if ( isplayer( ent ) && !isalive( ent ) ) + { + continue; + } + if ( ent damageconetrace( traceorigin, self ) > 0 ) + { + break; + } + else + { + } + } + if ( isDefined( watcher.activatesound ) ) + { + self playsound( watcher.activatesound ); + } + if ( isDefined( watcher.activatefx ) ) + { + self setclientflag( 4 ); + } + ent thread deathdodger( watcher.detectiongraceperiod ); + wait watcher.detectiongraceperiod; + if ( isplayer( ent ) && ent hasperk( "specialty_delayexplosive" ) ) + { + wait getDvarFloat( "perk_delayExplosiveTime" ); + } + self.origin = traceorigin; + if ( isDefined( self.owner ) && isplayer( self.owner ) ) + { + self [[ watcher.detonate ]]( self.owner ); + } + else self [[ watcher.detonate ]](); +} + +shouldaffectweaponobject( object, watcher ) +{ + pos = self.origin + vectorScale( ( 0, 0, 1 ), 32 ); + if ( isDefined( watcher.ignoredirection ) ) + { + return 1; + } + dirtopos = pos - object.origin; + objectforward = anglesToForward( object.angles ); + dist = vectordot( dirtopos, objectforward ); + if ( dist < watcher.detectionmindist ) + { + return 0; + } + dirtopos = vectornormalize( dirtopos ); + dot = vectordot( dirtopos, objectforward ); + return dot > watcher.detectiondot; +} + +deathdodger( graceperiod ) +{ + self endon( "death" ); + self endon( "disconnect" ); + wait ( 0,2 + graceperiod ); + self notify( "death_dodger" ); +} + +deleteondeath( ent ) +{ + self waittill_any( "death", "hacked" ); + wait 0,05; + if ( isDefined( ent ) ) + { + ent delete(); + } +} + +deleteonkillbrush( player ) +{ + player endon( "disconnect" ); + self endon( "death" ); + self endon( "stationary" ); + killbrushes = getentarray( "trigger_hurt", "classname" ); + while ( 1 ) + { + i = 0; + while ( i < killbrushes.size ) + { + if ( self istouching( killbrushes[ i ] ) ) + { + if ( self.origin[ 2 ] > player.origin[ 2 ] ) + { + break; + } + else + { + if ( isDefined( self ) ) + { + self delete(); + } + return; + } + i++; + } + } + wait 0,1; + } +} + +watchweaponobjectaltdetonation() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "alt_detonate" ); + while ( !isalive( self ) ) + { + continue; + } + watcher = 0; + while ( watcher < self.weaponobjectwatcherarray.size ) + { + if ( self.weaponobjectwatcherarray[ watcher ].altdetonate ) + { + self.weaponobjectwatcherarray[ watcher ] detonateweaponobjectarray( 0 ); + } + watcher++; + } + } +} + +watchweaponobjectaltdetonate() +{ + self endon( "disconnect" ); + self endon( "detonated" ); + level endon( "game_ended" ); + buttontime = 0; + for ( ;; ) + { + self waittill( "doubletap_detonate" ); + if ( !isalive( self ) ) + { + continue; + } + else + { + self notify( "alt_detonate" ); + wait 0,05; + } + } +} + +watchweaponobjectdetonation() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "detonate" ); + if ( self isusingoffhand() ) + { + weap = self getcurrentoffhand(); + } + else + { + weap = self getcurrentweapon(); + } + watcher = getweaponobjectwatcherbyweapon( weap ); + if ( isDefined( watcher ) ) + { + watcher detonateweaponobjectarray( 0 ); + } + } +} + +deleteweaponobjectson() +{ + while ( 1 ) + { + msg = self waittill_any_return( "disconnect", "joined_team", "joined_spectators", "death" ); + while ( msg == "death" ) + { + continue; + } + if ( !isDefined( self.weaponobjectwatcherarray ) ) + { + return; + } + watchers = []; + watcher = 0; + while ( watcher < self.weaponobjectwatcherarray.size ) + { + weaponobjectwatcher = spawnstruct(); + watchers[ watchers.size ] = weaponobjectwatcher; + weaponobjectwatcher.objectarray = []; + if ( isDefined( self.weaponobjectwatcherarray[ watcher ].objectarray ) ) + { + weaponobjectwatcher.objectarray = self.weaponobjectwatcherarray[ watcher ].objectarray; + } + watcher++; + } + wait 0,05; + watcher = 0; + while ( watcher < watchers.size ) + { + watchers[ watcher ] deleteweaponobjectarray(); + watcher++; + } + if ( msg == "disconnect" ) + { + return; + } + } +} + +saydamaged( orig, amount ) +{ +/# + i = 0; + while ( i < 60 ) + { + print3d( orig, "damaged! " + amount ); + wait 0,05; + i++; +#/ + } +} + +showheadicon( trigger ) +{ + triggerdetectid = trigger.detectid; + useid = -1; + index = 0; + while ( index < 4 ) + { + detectid = self.bombsquadicons[ index ].detectid; + if ( detectid == triggerdetectid ) + { + return; + } + if ( detectid == "" ) + { + useid = index; + } + index++; + } + if ( useid < 0 ) + { + return; + } + self.bombsquadids[ triggerdetectid ] = 1; + self.bombsquadicons[ useid ].x = trigger.origin[ 0 ]; + self.bombsquadicons[ useid ].y = trigger.origin[ 1 ]; + self.bombsquadicons[ useid ].z = trigger.origin[ 2 ] + 24 + 128; + self.bombsquadicons[ useid ] fadeovertime( 0,25 ); + self.bombsquadicons[ useid ].alpha = 1; + self.bombsquadicons[ useid ].detectid = trigger.detectid; + while ( isalive( self ) && isDefined( trigger ) && self istouching( trigger ) ) + { + wait 0,05; + } + if ( !isDefined( self ) ) + { + return; + } + self.bombsquadicons[ useid ].detectid = ""; + self.bombsquadicons[ useid ] fadeovertime( 0,25 ); + self.bombsquadicons[ useid ].alpha = 0; +} + +friendlyfirecheck( owner, attacker, forcedfriendlyfirerule ) +{ + if ( !isDefined( owner ) ) + { + return 1; + } + if ( !level.teambased ) + { + return 1; + } + friendlyfirerule = level.friendlyfire; + if ( isDefined( forcedfriendlyfirerule ) ) + { + friendlyfirerule = forcedfriendlyfirerule; + } + if ( friendlyfirerule != 0 ) + { + return 1; + } + if ( attacker == owner ) + { + return 1; + } + if ( isplayer( attacker ) ) + { + if ( !isDefined( attacker.pers[ "team" ] ) ) + { + return 1; + } + if ( attacker.pers[ "team" ] != owner.pers[ "team" ] ) + { + return 1; + } + } + else + { + if ( isai( attacker ) ) + { + if ( attacker.aiteam != owner.pers[ "team" ] ) + { + return 1; + } + } + else + { + if ( isvehicle( attacker ) ) + { + if ( isDefined( attacker.owner ) && isplayer( attacker.owner ) ) + { + if ( attacker.owner.pers[ "team" ] != owner.pers[ "team" ] ) + { + return 1; + } + } + } + } + } + return 0; +} + +onspawnhatchettrigger( watcher, player ) +{ + self endon( "death" ); + self setowner( player ); + self setteam( player.pers[ "team" ] ); + self.owner = player; + self.oldangles = self.angles; + self waittillnotmoving(); + waittillframeend; + if ( player.pers[ "team" ] == "spectator" ) + { + return; + } + triggerorigin = self.origin; + triggerparentent = undefined; + if ( isDefined( self.stucktoplayer ) ) + { + if ( isalive( self.stucktoplayer ) || !isDefined( self.stucktoplayer.body ) ) + { + if ( isalive( self.stucktoplayer ) ) + { + triggerparentent = self; + self unlink(); + self.angles = self.oldangles; + self launch( vectorScale( ( 0, 0, 1 ), 5 ) ); + self waittillnotmoving(); + waittillframeend; + } + else + { + triggerparentent = self.stucktoplayer; + } + } + else + { + triggerparentent = self.stucktoplayer.body; + } + } + if ( isDefined( triggerparentent ) ) + { + triggerorigin = triggerparentent.origin + vectorScale( ( 0, 0, 1 ), 10 ); + } + self.hatchetpickuptrigger = spawn( "trigger_radius", triggerorigin, 0, 50, 50 ); + self.hatchetpickuptrigger enablelinkto(); + self.hatchetpickuptrigger linkto( self ); + if ( isDefined( triggerparentent ) ) + { + self.hatchetpickuptrigger linkto( triggerparentent ); + } + self thread watchhatchettrigger( self.hatchetpickuptrigger, watcher.pickup, watcher.pickupsoundplayer, watcher.pickupsound ); +/# + thread switch_team( self, watcher.weapon, player ); +#/ + self thread watchshutdown( player ); +} + +watchhatchettrigger( trigger, callback, playersoundonuse, npcsoundonuse ) +{ + self endon( "delete" ); + self endon( "hacked" ); + while ( 1 ) + { + trigger waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + if ( isDefined( trigger.claimedby ) && player != trigger.claimedby ) + { + continue; + } + while ( !player hasweapon( self.name ) ) + { + continue; + } + curr_ammo = player getweaponammostock( "hatchet_mp" ); + maxammo = weaponmaxammo( "hatchet_mp" ); + if ( player.grenadetypeprimary == "hatchet_mp" ) + { + maxammo = player.grenadetypeprimarycount; + } + else + { + if ( isDefined( player.grenadetypesecondary ) && player.grenadetypesecondary == "hatchet_mp" ) + { + maxammo = player.grenadetypesecondarycount; + } + } + while ( curr_ammo >= maxammo ) + { + continue; + } + if ( isDefined( playersoundonuse ) ) + { + player playlocalsound( playersoundonuse ); + } + if ( isDefined( npcsoundonuse ) ) + { + player playsound( npcsoundonuse ); + } + self thread [[ callback ]]( player ); + } +} + +onspawnretrievableweaponobject( watcher, player ) +{ + self endon( "death" ); + self endon( "hacked" ); + if ( ishacked() ) + { + self thread watchshutdown( player ); + return; + } + self setowner( player ); + self setteam( player.pers[ "team" ] ); + self.owner = player; + self.oldangles = self.angles; + self waittillnotmoving(); + if ( isDefined( watcher.activationdelay ) ) + { + wait watcher.activationdelay; + } + waittillframeend; + if ( player.pers[ "team" ] == "spectator" ) + { + return; + } + triggerorigin = self.origin; + triggerparentent = undefined; + if ( isDefined( self.stucktoplayer ) ) + { + if ( isalive( self.stucktoplayer ) || !isDefined( self.stucktoplayer.body ) ) + { + triggerparentent = self.stucktoplayer; + } + else + { + triggerparentent = self.stucktoplayer.body; + } + } + if ( isDefined( triggerparentent ) ) + { + triggerorigin = triggerparentent.origin + vectorScale( ( 0, 0, 1 ), 10 ); + } + else + { + up = anglesToUp( self.angles ); + triggerorigin = self.origin + up; + } + if ( isDefined( watcher.adjusttriggerorigin ) ) + { + triggerorigin = self [[ watcher.adjusttriggerorigin ]]( triggerorigin ); + } + self.pickuptrigger = spawn( "trigger_radius_use", triggerorigin ); + self.pickuptrigger sethintlowpriority( 1 ); + self.pickuptrigger setcursorhint( "HINT_NOICON", self ); + self.pickuptrigger enablelinkto(); + self.pickuptrigger linkto( self ); + self.pickuptrigger setinvisibletoall(); + self.pickuptrigger setvisibletoplayer( player ); + if ( isDefined( level.retrievehints[ watcher.name ] ) ) + { + self.pickuptrigger sethintstring( level.retrievehints[ watcher.name ].hint ); + } + else + { + self.pickuptrigger sethintstring( &"MP_GENERIC_PICKUP" ); + } + if ( level.teambased ) + { + self.pickuptrigger setteamfortrigger( player.pers[ "team" ] ); + } + else + { + self.pickuptrigger setteamfortrigger( "none" ); + } + if ( isDefined( triggerparentent ) ) + { + self.pickuptrigger linkto( triggerparentent ); + } + if ( watcher.enemydestroy ) + { + self.enemytrigger = spawn( "trigger_radius_use", triggerorigin ); + self.enemytrigger setcursorhint( "HINT_NOICON", self ); + self.enemytrigger enablelinkto(); + self.enemytrigger linkto( self ); + self.enemytrigger setinvisibletoplayer( player ); + if ( level.teambased ) + { + self.enemytrigger setexcludeteamfortrigger( player.team ); + self.enemytrigger.triggerteamignore = self.team; + } + if ( isDefined( level.destroyhints[ watcher.name ] ) ) + { + self.enemytrigger sethintstring( level.destroyhints[ watcher.name ].hint ); + } + else + { + self.enemytrigger sethintstring( &"MP_GENERIC_DESTROY" ); + } + self thread watchusetrigger( self.enemytrigger, watcher.ondestroyed ); + } + self thread watchusetrigger( self.pickuptrigger, watcher.pickup, watcher.pickupsoundplayer, watcher.pickupsound ); +/# + thread switch_team( self, watcher.weapon, player ); +#/ + if ( isDefined( watcher.pickup_trigger_listener ) ) + { + self thread [[ watcher.pickup_trigger_listener ]]( self.pickuptrigger, player ); + } + self thread watchshutdown( player ); +} + +watch_trigger_visibility( triggers, weap_name ) +{ + self notify( "watchTriggerVisibility" ); + self endon( "watchTriggerVisibility" ); + self endon( "death" ); + self endon( "hacked" ); + max_ammo = weaponmaxammo( weap_name ); + start_ammo = weaponstartammo( weap_name ); + ammo_to_check = 0; + while ( 1 ) + { + players = level.players; + i = 0; + while ( i < players.size ) + { + if ( players[ i ] hasweapon( weap_name ) ) + { + ammo_to_check = max_ammo; + if ( self.owner == players[ i ] ) + { + curr_ammo = players[ i ] getweaponammostock( weap_name ) + players[ i ] getweaponammoclip( weap_name ); + if ( weap_name == "hatchet_mp" ) + { + curr_ammo = players[ i ] getweaponammostock( weap_name ); + } + if ( curr_ammo < ammo_to_check ) + { + triggers[ "owner_pickup" ] setvisibletoplayer( players[ i ] ); + triggers[ "enemy_pickup" ] setinvisibletoplayer( players[ i ] ); + } + else + { + triggers[ "owner_pickup" ] setinvisibletoplayer( players[ i ] ); + triggers[ "enemy_pickup" ] setinvisibletoplayer( players[ i ] ); + } + } + else curr_ammo = players[ i ] getweaponammostock( weap_name ) + players[ i ] getweaponammoclip( weap_name ); + if ( weap_name == "hatchet_mp" ) + { + curr_ammo = players[ i ] getweaponammostock( weap_name ); + } + if ( curr_ammo < ammo_to_check ) + { + triggers[ "owner_pickup" ] setinvisibletoplayer( players[ i ] ); + triggers[ "enemy_pickup" ] setvisibletoplayer( players[ i ] ); + } + else + { + triggers[ "owner_pickup" ] setinvisibletoplayer( players[ i ] ); + triggers[ "enemy_pickup" ] setinvisibletoplayer( players[ i ] ); + } + i++; + continue; + } + else + { + triggers[ "owner_pickup" ] setinvisibletoplayer( players[ i ] ); + triggers[ "enemy_pickup" ] setinvisibletoplayer( players[ i ] ); + } + i++; + } + wait 0,05; + } +} + +destroyent() +{ + self delete(); +} + +pickup( player ) +{ + if ( self.name != "hatchet_mp" && isDefined( self.owner ) && self.owner != player ) + { + return; + } + self.playdialog = 0; + self destroyent(); + player giveweapon( self.name ); + clip_ammo = player getweaponammoclip( self.name ); + clip_max_ammo = weaponclipsize( self.name ); + if ( clip_ammo < clip_max_ammo ) + { + clip_ammo++; + } + player setweaponammoclip( self.name, clip_ammo ); +} + +ondestroyed( attacker ) +{ + playfx( level._effect[ "tacticalInsertionFizzle" ], self.origin ); + self playsound( "dst_tac_insert_break" ); + self.owner maps/mp/gametypes_zm/_globallogic_audio::leaderdialogonplayer( "equipment_destroyed", "item_destroyed" ); + self delete(); +} + +watchshutdown( player ) +{ + self waittill_any( "death", "hacked" ); + pickuptrigger = self.pickuptrigger; + hackertrigger = self.hackertrigger; + hatchetpickuptrigger = self.hatchetpickuptrigger; + enemytrigger = self.enemytrigger; + if ( isDefined( pickuptrigger ) ) + { + pickuptrigger delete(); + } + if ( isDefined( hackertrigger ) ) + { + if ( isDefined( hackertrigger.progressbar ) ) + { + hackertrigger.progressbar destroyelem(); + hackertrigger.progresstext destroyelem(); + } + hackertrigger delete(); + } + if ( isDefined( hatchetpickuptrigger ) ) + { + hatchetpickuptrigger delete(); + } + if ( isDefined( enemytrigger ) ) + { + enemytrigger delete(); + } +} + +watchusetrigger( trigger, callback, playersoundonuse, npcsoundonuse ) +{ + self endon( "delete" ); + self endon( "hacked" ); + while ( 1 ) + { + trigger waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + while ( !player isonground() ) + { + continue; + } + if ( isDefined( trigger.triggerteam ) && player.pers[ "team" ] != trigger.triggerteam ) + { + continue; + } + if ( isDefined( trigger.triggerteamignore ) && player.team == trigger.triggerteamignore ) + { + continue; + } + if ( isDefined( trigger.claimedby ) && player != trigger.claimedby ) + { + continue; + } + grenade = player.throwinggrenade; + isequipment = isweaponequipment( player getcurrentweapon() ); + if ( isDefined( isequipment ) && isequipment ) + { + grenade = 0; + } + if ( player usebuttonpressed() && !grenade && !player meleebuttonpressed() ) + { + if ( isDefined( playersoundonuse ) ) + { + player playlocalsound( playersoundonuse ); + } + if ( isDefined( npcsoundonuse ) ) + { + player playsound( npcsoundonuse ); + } + self thread [[ callback ]]( player ); + } + } +} + +createretrievablehint( name, hint ) +{ + retrievehint = spawnstruct(); + retrievehint.name = name; + retrievehint.hint = hint; + level.retrievehints[ name ] = retrievehint; +} + +createhackerhint( name, hint ) +{ + hackerhint = spawnstruct(); + hackerhint.name = name; + hackerhint.hint = hint; + level.hackerhints[ name ] = hackerhint; +} + +createdestroyhint( name, hint ) +{ + destroyhint = spawnstruct(); + destroyhint.name = name; + destroyhint.hint = hint; + level.destroyhints[ name ] = destroyhint; +} + +attachreconmodel( modelname, owner ) +{ + if ( !isDefined( self ) ) + { + return; + } + reconmodel = spawn( "script_model", self.origin ); + reconmodel.angles = self.angles; + reconmodel setmodel( modelname ); + reconmodel.model_name = modelname; + reconmodel linkto( self ); + reconmodel setcontents( 0 ); + reconmodel resetreconmodelvisibility( owner ); + reconmodel thread watchreconmodelfordeath( self ); + reconmodel thread resetreconmodelonevent( "joined_team", owner ); + reconmodel thread resetreconmodelonevent( "player_spawned", owner ); +} + +resetreconmodelvisibility( owner ) +{ + if ( !isDefined( self ) ) + { + return; + } + self setinvisibletoall(); + self setforcenocull(); + if ( !isDefined( owner ) ) + { + return; + } + i = 0; + while ( i < level.players.size ) + { + if ( !level.players[ i ] hasperk( "specialty_detectexplosive" ) && !level.players[ i ] hasperk( "specialty_showenemyequipment" ) ) + { + i++; + continue; + } + else + { + if ( level.players[ i ].team == "spectator" ) + { + i++; + continue; + } + else hasreconmodel = 0; + if ( level.players[ i ] hasperk( "specialty_detectexplosive" ) ) + { + switch( self.model_name ) + { + case "t6_wpn_c4_world_detect": + case "t6_wpn_claymore_world_detect": + hasreconmodel = 1; + break; + break; + default: + } + } + if ( level.players[ i ] hasperk( "specialty_showenemyequipment" ) ) + { + switch( self.model_name ) + { + case "t5_weapon_scrambler_world_detect": + case "t6_wpn_bouncing_betty_world_detect": + case "t6_wpn_c4_world_detect": + case "t6_wpn_claymore_world_detect": + case "t6_wpn_motion_sensor_world_detect": + case "t6_wpn_tac_insert_detect": + case "t6_wpn_taser_mine_world_detect": + case "t6_wpn_trophy_system_world_detect": + hasreconmodel = 1; + break; + break; + default: + } + } + if ( !hasreconmodel ) + { + i++; + continue; + } + else isenemy = 1; + if ( level.teambased ) + { + if ( level.players[ i ].team == owner.team ) + { + isenemy = 0; + } + } + else + { + if ( level.players[ i ] == owner ) + { + isenemy = 0; + } + } + if ( isenemy ) + { + self setvisibletoplayer( level.players[ i ] ); + } + } + i++; + } + } + } +} + +watchreconmodelfordeath( parentent ) +{ + self endon( "death" ); + parentent waittill_any( "death", "hacked" ); + self delete(); +} + +resetreconmodelonevent( eventname, owner ) +{ + self endon( "death" ); + for ( ;; ) + { + level waittill( eventname, newowner ); + if ( isDefined( newowner ) ) + { + owner = newowner; + } + self resetreconmodelvisibility( owner ); + } +} + +switch_team( entity, weapon_name, owner ) +{ +/# +#/ +} diff --git a/patch_zm/maps/mp/gametypes_zm/_weapons.gsc b/patch_zm/maps/mp/gametypes_zm/_weapons.gsc new file mode 100644 index 0000000..c70cd9c --- /dev/null +++ b/patch_zm/maps/mp/gametypes_zm/_weapons.gsc @@ -0,0 +1,2029 @@ +#include maps/mp/gametypes_zm/_gameobjects; +#include maps/mp/gametypes_zm/_shellshock; +#include maps/mp/gametypes_zm/_globallogic_utils; +#include maps/mp/zombies/_zm_pers_upgrades_functions; +#include maps/mp/_challenges; +#include maps/mp/gametypes_zm/_weapons; +#include maps/mp/_bb; +#include maps/mp/gametypes_zm/_weapon_utils; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + precacheitem( "knife_mp" ); + precacheitem( "knife_held_mp" ); + precacheitem( "dogs_mp" ); + precacheitem( "dog_bite_mp" ); + precacheitem( "explosive_bolt_mp" ); + precachemodel( "t6_wpn_claymore_world_detect" ); + precachemodel( "t6_wpn_c4_world_detect" ); + precachemodel( "t5_weapon_scrambler_world_detect" ); + precachemodel( "t6_wpn_tac_insert_detect" ); + precachemodel( "t6_wpn_taser_mine_world_detect" ); + precachemodel( "t6_wpn_motion_sensor_world_detect" ); + precachemodel( "t6_wpn_trophy_system_world_detect" ); + precachemodel( "t6_wpn_bouncing_betty_world_detect" ); + precachemodel( "t5_weapon_camera_head_world" ); + precacheitem( "scavenger_item_mp" ); + precacheitem( "scavenger_item_hack_mp" ); + precacheshader( "hud_scavenger_pickup" ); + precacheshellshock( "default" ); + precacheshellshock( "concussion_grenade_mp" ); + precacheshellshock( "tabun_gas_mp" ); + precacheshellshock( "tabun_gas_nokick_mp" ); + precacheshellshock( "proximity_grenade" ); + precacheshellshock( "proximity_grenade_exit" ); + level.missileentities = []; + level.hackertooltargets = []; + if ( !isDefined( level.grenadelauncherdudtime ) ) + { + level.grenadelauncherdudtime = 0; + } + if ( !isDefined( level.throwngrenadedudtime ) ) + { + level.throwngrenadedudtime = 0; + } + level thread onplayerconnect(); + maps/mp/gametypes_zm/_weaponobjects::init(); + if ( !is_false( level._uses_sticky_grenades ) ) + { + maps/mp/_sticky_grenade::init(); + } +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player.usedweapons = 0; + player.lastfiretime = 0; + player.hits = 0; + player scavenger_hud_create(); + player thread onplayerspawned(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self.concussionendtime = 0; + self.hasdonecombat = 0; + self.shielddamageblocked = 0; + self thread watchweaponusage(); + self thread watchgrenadeusage(); + self thread watchmissileusage(); + self thread watchweaponchange(); + self thread watchturretuse(); + self thread watchriotshielduse(); + self thread trackweapon(); + self.droppeddeathweapon = undefined; + self.tookweaponfrom = []; + self.pickedupweaponkills = []; + self thread updatestowedweapon(); + } +} + +watchturretuse() +{ + self endon( "death" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "turretownerchange", turret ); + self thread watchfortowfire( turret ); + } +} + +watchfortowfire( turret ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "turretownerchange" ); + while ( 1 ) + { + self waittill( "turret_tow_fire" ); + self thread watchmissleunlink( turret ); + self waittill( "turret_tow_unlink" ); + } +} + +watchmissleunlink( turret ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "turretownerchange" ); + self waittill( "turret_tow_unlink" ); + self relinktoturret( turret ); +} + +watchweaponchange() +{ + self endon( "death" ); + self endon( "disconnect" ); + self.lastdroppableweapon = self getcurrentweapon(); + self.hitsthismag = []; + weapon = self getcurrentweapon(); + if ( isprimaryweapon( weapon ) && !isDefined( self.hitsthismag[ weapon ] ) ) + { + self.hitsthismag[ weapon ] = weaponclipsize( weapon ); + } + while ( 1 ) + { + previous_weapon = self getcurrentweapon(); + self waittill( "weapon_change", newweapon ); + if ( maydropweapon( newweapon ) ) + { + self.lastdroppableweapon = newweapon; + } + if ( newweapon != "none" ) + { + if ( !isprimaryweapon( newweapon ) && issidearm( newweapon ) && !isDefined( self.hitsthismag[ newweapon ] ) ) + { + self.hitsthismag[ newweapon ] = weaponclipsize( newweapon ); + } + } + } +} + +watchriotshielduse() +{ +} + +updatelastheldweapontimings( newtime ) +{ + if ( isDefined( self.currentweapon ) && isDefined( self.currentweaponstarttime ) ) + { + totaltime = int( ( newtime - self.currentweaponstarttime ) / 1000 ); + if ( totaltime > 0 ) + { + self addweaponstat( self.currentweapon, "timeUsed", totaltime ); + self.currentweaponstarttime = newtime; + } + } +} + +updateweapontimings( newtime ) +{ + if ( self is_bot() ) + { + return; + } + updatelastheldweapontimings( newtime ); + if ( !isDefined( self.staticweaponsstarttime ) ) + { + return; + } + totaltime = int( ( newtime - self.staticweaponsstarttime ) / 1000 ); + if ( totaltime < 0 ) + { + return; + } + self.staticweaponsstarttime = newtime; + while ( isDefined( self.weapon_array_grenade ) ) + { + i = 0; + while ( i < self.weapon_array_grenade.size ) + { + self addweaponstat( self.weapon_array_grenade[ i ], "timeUsed", totaltime ); + i++; + } + } + while ( isDefined( self.weapon_array_inventory ) ) + { + i = 0; + while ( i < self.weapon_array_inventory.size ) + { + self addweaponstat( self.weapon_array_inventory[ i ], "timeUsed", totaltime ); + i++; + } + } + while ( isDefined( self.killstreak ) ) + { + i = 0; + while ( i < self.killstreak.size ) + { + killstreakweapon = level.menureferenceforkillstreak[ self.killstreak[ i ] ]; + if ( isDefined( killstreakweapon ) ) + { + self addweaponstat( killstreakweapon, "timeUsed", totaltime ); + } + i++; + } + } + while ( level.rankedmatch && level.perksenabled ) + { + perksindexarray = []; + specialtys = self.specialty; + if ( !isDefined( specialtys ) ) + { + return; + } + if ( !isDefined( self.class ) ) + { + return; + } + while ( isDefined( self.class_num ) ) + { + numspecialties = 0; + while ( numspecialties < level.maxspecialties ) + { + perk = self getloadoutitem( self.class_num, "specialty" + ( numspecialties + 1 ) ); + if ( perk != 0 ) + { + perksindexarray[ perk ] = 1; + } + numspecialties++; + } + perkindexarraykeys = getarraykeys( perksindexarray ); + i = 0; + while ( i < perkindexarraykeys.size ) + { + if ( perksindexarray[ perkindexarraykeys[ i ] ] == 1 ) + { + self adddstat( "itemStats", perkindexarraykeys[ i ], "stats", "timeUsed", "statValue", totaltime ); + } + i++; + } + } + } +} + +trackweapon() +{ + currentweapon = self getcurrentweapon(); + currenttime = getTime(); + spawnid = getplayerspawnid( self ); + while ( 1 ) + { + event = self waittill_any_return( "weapon_change", "death", "disconnect" ); + newtime = getTime(); + if ( event == "weapon_change" ) + { + self maps/mp/_bb::commitweapondata( spawnid, currentweapon, currenttime ); + newweapon = self getcurrentweapon(); + if ( newweapon != "none" && newweapon != currentweapon ) + { + updatelastheldweapontimings( newtime ); + currentweapon = newweapon; + currenttime = newtime; + } + continue; + } + else + { + if ( event != "disconnect" ) + { + self maps/mp/_bb::commitweapondata( spawnid, currentweapon, currenttime ); + updateweapontimings( newtime ); + } + return; + } + } +} + +maydropweapon( weapon ) +{ + if ( level.disableweapondrop == 1 ) + { + return 0; + } + if ( weapon == "none" ) + { + return 0; + } + if ( ishackweapon( weapon ) ) + { + return 0; + } + invtype = weaponinventorytype( weapon ); + if ( invtype != "primary" ) + { + return 0; + } + if ( weapon == "none" ) + { + return 0; + } + return 1; +} + +dropweaponfordeath( attacker ) +{ + if ( level.disableweapondrop == 1 ) + { + return; + } + weapon = self.lastdroppableweapon; + if ( isDefined( self.droppeddeathweapon ) ) + { + return; + } + if ( !isDefined( weapon ) ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: not defined" ); +#/ + } + return; + } + if ( weapon == "none" ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: weapon == none" ); +#/ + } + return; + } + if ( !self hasweapon( weapon ) ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: don't have it anymore (" + weapon + ")" ); +#/ + } + return; + } + if ( !self anyammoforweaponmodes( weapon ) ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: no ammo for weapon modes" ); +#/ + } + return; + } + if ( !shoulddroplimitedweapon( weapon, self ) ) + { + return; + } + clipammo = self getweaponammoclip( weapon ); + stockammo = self getweaponammostock( weapon ); + clip_and_stock_ammo = clipammo + stockammo; + if ( !clip_and_stock_ammo ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: no ammo" ); +#/ + } + return; + } + stockmax = weaponmaxammo( weapon ); + if ( stockammo > stockmax ) + { + stockammo = stockmax; + } + item = self dropitem( weapon ); + if ( !isDefined( item ) ) + { +/# + iprintlnbold( "dropItem: was not able to drop weapon " + weapon ); +#/ + return; + } +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "dropped weapon: " + weapon ); +#/ + } + droplimitedweapon( weapon, self, item ); + self.droppeddeathweapon = 1; + item itemweaponsetammo( clipammo, stockammo ); + item.owner = self; + item.ownersattacker = attacker; + item thread watchpickup(); + item thread deletepickupafterawhile(); +} + +dropweapontoground( weapon ) +{ + if ( !isDefined( weapon ) ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: not defined" ); +#/ + } + return; + } + if ( weapon == "none" ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: weapon == none" ); +#/ + } + return; + } + if ( !self hasweapon( weapon ) ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: don't have it anymore (" + weapon + ")" ); +#/ + } + return; + } + if ( !self anyammoforweaponmodes( weapon ) ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: no ammo for weapon modes" ); +#/ + } + switch( weapon ) + { + case "m202_flash_mp": + case "m220_tow_mp": + case "m32_mp": + case "minigun_mp": + case "mp40_blinged_mp": + self takeweapon( weapon ); + break; + default: + } + return; + } + if ( !shoulddroplimitedweapon( weapon, self ) ) + { + return; + } + clipammo = self getweaponammoclip( weapon ); + stockammo = self getweaponammostock( weapon ); + clip_and_stock_ammo = clipammo + stockammo; + if ( !clip_and_stock_ammo ) + { +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "didn't drop weapon: no ammo" ); +#/ + } + return; + } + stockmax = weaponmaxammo( weapon ); + if ( stockammo > stockmax ) + { + stockammo = stockmax; + } + item = self dropitem( weapon ); +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "dropped weapon: " + weapon ); +#/ + } + droplimitedweapon( weapon, self, item ); + item itemweaponsetammo( clipammo, stockammo ); + item.owner = self; + item thread watchpickup(); + item thread deletepickupafterawhile(); + } +} + +deletepickupafterawhile() +{ + self endon( "death" ); + wait 60; + if ( !isDefined( self ) ) + { + return; + } + self delete(); +} + +getitemweaponname() +{ + classname = self.classname; +/# + assert( getsubstr( classname, 0, 7 ) == "weapon_" ); +#/ + weapname = getsubstr( classname, 7 ); + return weapname; +} + +watchpickup() +{ + self endon( "death" ); + weapname = self getitemweaponname(); + while ( 1 ) + { + self waittill( "trigger", player, droppeditem ); + if ( isDefined( droppeditem ) ) + { + break; + } + else + { + } + } +/# + if ( getDvar( #"08F7FC88" ) == "1" ) + { + println( "picked up weapon: " + weapname + ", " + isDefined( self.ownersattacker ) ); +#/ + } +/# + assert( isDefined( player.tookweaponfrom ) ); +#/ +/# + assert( isDefined( player.pickedupweaponkills ) ); +#/ + droppedweaponname = droppeditem getitemweaponname(); + if ( isDefined( player.tookweaponfrom[ droppedweaponname ] ) ) + { + droppeditem.owner = player.tookweaponfrom[ droppedweaponname ]; + droppeditem.ownersattacker = player; + } + droppeditem thread watchpickup(); + if ( isDefined( self.ownersattacker ) && self.ownersattacker == player ) + { + player.tookweaponfrom[ weapname ] = self.owner; + player.pickedupweaponkills[ weapname ] = 0; + } + else } + +itemremoveammofromaltmodes() +{ + origweapname = self getitemweaponname(); + curweapname = weaponaltweaponname( origweapname ); + altindex = 1; + while ( curweapname != "none" && curweapname != origweapname ) + { + self itemweaponsetammo( 0, 0, altindex ); + curweapname = weaponaltweaponname( curweapname ); + altindex++; + } +} + +dropoffhand() +{ + grenadetypes = []; + index = 0; + while ( index < grenadetypes.size ) + { + if ( !self hasweapon( grenadetypes[ index ] ) ) + { + index++; + continue; + } + else count = self getammocount( grenadetypes[ index ] ); + if ( !count ) + { + index++; + continue; + } + else + { + self dropitem( grenadetypes[ index ] ); + } + index++; + } +} + +watchweaponusage() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self.usedkillstreakweapon = []; + self.usedkillstreakweapon[ "minigun_mp" ] = 0; + self.usedkillstreakweapon[ "m32_mp" ] = 0; + self.usedkillstreakweapon[ "m202_flash_mp" ] = 0; + self.usedkillstreakweapon[ "m220_tow_mp" ] = 0; + self.usedkillstreakweapon[ "mp40_blinged_mp" ] = 0; + self.killstreaktype = []; + self.killstreaktype[ "minigun_mp" ] = "minigun_mp"; + self.killstreaktype[ "m32_mp" ] = "m32_mp"; + self.killstreaktype[ "m202_flash_mp" ] = "m202_flash_mp"; + self.killstreaktype[ "m220_tow_mp" ] = "m220_tow_mp"; + self.killstreaktype[ "mp40_blinged_mp" ] = "mp40_blinged_drop_mp"; + for ( ;; ) + { + self waittill( "weapon_fired", curweapon ); + self.lastfiretime = getTime(); + self.hasdonecombat = 1; + if ( maps/mp/gametypes_zm/_weapons::isprimaryweapon( curweapon ) || maps/mp/gametypes_zm/_weapons::issidearm( curweapon ) ) + { + if ( isDefined( self.hitsthismag[ curweapon ] ) ) + { + self thread updatemagshots( curweapon ); + } + } + switch( weaponclass( curweapon ) ) + { + case "rifle": + if ( curweapon == "crossbow_explosive_mp" ) + { + level.globalcrossbowfired++; + self addweaponstat( curweapon, "shots", 1 ); + self thread begingrenadetracking(); + break; + continue; + } + else case "mg": + case "pistol": + case "smg": + case "spread": + self trackweaponfire( curweapon ); + level.globalshotsfired++; + break; + continue; + case "grenade": + case "rocketlauncher": + self addweaponstat( curweapon, "shots", 1 ); + break; + continue; + default: + } + } + } +} + +updatemagshots( weaponname ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "updateMagShots_" + weaponname ); + self.hitsthismag[ weaponname ]--; + + wait 0,05; + self.hitsthismag[ weaponname ] = weaponclipsize( weaponname ); +} + +checkhitsthismag( weaponname ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "updateMagShots_" + weaponname ); + waittillframeend; + if ( isDefined( self.hitsthismag[ weaponname ] ) && self.hitsthismag[ weaponname ] == 0 ) + { + if ( !sessionmodeiszombiesgame() ) + { + weaponclass = getweaponclass( weaponname ); + maps/mp/_challenges::fullclipnomisses( weaponclass, weaponname ); + } + self.hitsthismag[ weaponname ] = weaponclipsize( weaponname ); + } +} + +trackweaponfire( curweapon ) +{ + shotsfired = 1; + if ( isDefined( self.laststandparams ) && self.laststandparams.laststandstarttime == getTime() ) + { + self.hits = 0; + return; + } + pixbeginevent( "trackWeaponFire" ); + if ( is_true( level.pers_upgrade_sniper ) ) + { + maps/mp/zombies/_zm_pers_upgrades_functions::pers_sniper_player_fires( curweapon, self.hits ); + } + self addweaponstat( curweapon, "shots", shotsfired ); + self addweaponstat( curweapon, "hits", self.hits ); + if ( isDefined( level.add_client_stat ) ) + { + self [[ level.add_client_stat ]]( "total_shots", shotsfired ); + self [[ level.add_client_stat ]]( "hits", self.hits ); + } + else + { + self addplayerstat( "total_shots", shotsfired ); + self addplayerstat( "hits", self.hits ); + self addplayerstat( "misses", int( max( 0, shotsfired - self.hits ) ) ); + } + self incrementplayerstat( "total_shots", shotsfired ); + self incrementplayerstat( "hits", self.hits ); + self incrementplayerstat( "misses", int( max( 0, shotsfired - self.hits ) ) ); + self maps/mp/_bb::bbaddtostat( "shots", shotsfired ); + self maps/mp/_bb::bbaddtostat( "hits", self.hits ); + self.hits = 0; + pixendevent(); +} + +checkhit( sweapon ) +{ + switch( weaponclass( sweapon ) ) + { + case "mg": + case "pistol": + case "rifle": + case "smg": + self.hits++; + break; + case "pistol spread": + case "spread": + self.hits = 1; + break; + default: + } + waittillframeend; + if ( isDefined( self.hitsthismag ) && isDefined( self.hitsthismag[ sweapon ] ) ) + { + self thread checkhitsthismag( sweapon ); + } + if ( sweapon != "bazooka_mp" || isstrstart( sweapon, "t34" ) && isstrstart( sweapon, "panzer" ) ) + { + self addweaponstat( sweapon, "hits", 1 ); + } + } +} + +watchgrenadeusage() +{ + self endon( "death" ); + self endon( "disconnect" ); + self.throwinggrenade = 0; + self.gotpullbacknotify = 0; + self thread beginothergrenadetracking(); + self thread watchforthrowbacks(); + self thread watchforgrenadeduds(); + self thread watchforgrenadelauncherduds(); + for ( ;; ) + { + self waittill( "grenade_pullback", weaponname ); + self addweaponstat( weaponname, "shots", 1 ); + self.hasdonecombat = 1; + self.throwinggrenade = 1; + self.gotpullbacknotify = 1; + if ( weaponname == "satchel_charge_mp" ) + { + self thread beginsatcheltracking(); + } + self thread begingrenadetracking(); + } +} + +watchmissileusage() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + for ( ;; ) + { + self waittill( "missile_fire", missile, weapon_name ); + self.hasdonecombat = 1; +/# + assert( isDefined( missile ) ); +#/ + level.missileentities[ level.missileentities.size ] = missile; + missile thread watchmissiledeath(); + } +} + +watchmissiledeath() +{ + self waittill( "death" ); + arrayremovevalue( level.missileentities, self ); +} + +dropweaponstoground( origin, radius ) +{ + weapons = getdroppedweapons(); + i = 0; + while ( i < weapons.size ) + { + if ( distancesquared( origin, weapons[ i ].origin ) < ( radius * radius ) ) + { + trace = bullettrace( weapons[ i ].origin, weapons[ i ].origin + vectorScale( ( 0, 0, 1 ), 2000 ), 0, weapons[ i ] ); + weapons[ i ].origin = trace[ "position" ]; + } + i++; + } +} + +dropgrenadestoground( origin, radius ) +{ + grenades = getentarray( "grenade", "classname" ); + i = 0; + while ( i < grenades.size ) + { + if ( distancesquared( origin, grenades[ i ].origin ) < ( radius * radius ) ) + { + grenades[ i ] launch( vectorScale( ( 0, 0, 1 ), 5 ) ); + } + i++; + } +} + +watchgrenadecancel() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "grenade_fire" ); + self waittill( "weapon_change" ); + self.throwinggrenade = 0; + self.gotpullbacknotify = 0; +} + +begingrenadetracking() +{ + self endon( "death" ); + self endon( "disconnect" ); + starttime = getTime(); + self thread watchgrenadecancel(); + self waittill( "grenade_fire", grenade, weaponname ); +/# + assert( isDefined( grenade ) ); +#/ + level.missileentities[ level.missileentities.size ] = grenade; + grenade thread watchmissiledeath(); + if ( grenade maps/mp/gametypes_zm/_weaponobjects::ishacked() ) + { + return; + } + bbprint( "mpequipmentuses", "gametime %d spawnid %d weaponname %s", getTime(), getplayerspawnid( self ), weaponname ); + if ( ( getTime() - starttime ) > 1000 ) + { + grenade.iscooked = 1; + } + switch( weaponname ) + { + case "frag_grenade_zm": + case "sticky_grenade_zm": + self addweaponstat( weaponname, "used", 1 ); + case "explosive_bolt_zm": + grenade.originalowner = self; + break; + } + if ( weaponname == "sticky_grenade_zm" || weaponname == "frag_grenade_zm" ) + { + grenade setteam( self.pers[ "team" ] ); + grenade setowner( self ); + } + self.throwinggrenade = 0; + } +} + +beginothergrenadetracking() +{ +} + +checkstucktoplayer( deleteonteamchange, awardscoreevent, weaponname ) +{ + self endon( "death" ); + self waittill( "stuck_to_player", player ); + if ( isDefined( player ) ) + { + if ( deleteonteamchange ) + { + self thread stucktoplayerteamchange( player ); + } + if ( awardscoreevent && isDefined( self.originalowner ) ) + { + if ( self.originalowner isenemyplayer( player ) ) + { + } + } + self.stucktoplayer = player; + } +} + +checkhatchetbounce() +{ + self endon( "stuck_to_player" ); + self endon( "death" ); + self waittill( "grenade_bounce" ); + self.bounced = 1; +} + +stucktoplayerteamchange( player ) +{ + self endon( "death" ); + player endon( "disconnect" ); + originalteam = player.pers[ "team" ]; + while ( 1 ) + { + player waittill( "joined_team" ); + if ( player.pers[ "team" ] != originalteam ) + { + self detonate(); + return; + } + } +} + +beginsatcheltracking() +{ + self endon( "death" ); + self endon( "disconnect" ); + self waittill_any( "grenade_fire", "weapon_change" ); + self.throwinggrenade = 0; +} + +watchforthrowbacks() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "grenade_fire", grenade, weapname ); + if ( self.gotpullbacknotify ) + { + self.gotpullbacknotify = 0; + continue; + } + else if ( !issubstr( weapname, "frag_" ) ) + { + continue; + } + else + { + grenade.threwback = 1; + grenade.originalowner = self; + } + } +} + +registergrenadelauncherduddvar( dvarstring, defaultvalue, minvalue, maxvalue ) +{ + dvarstring = "scr_" + dvarstring + "_grenadeLauncherDudTime"; + if ( getDvar( dvarstring ) == "" ) + { + setdvar( dvarstring, defaultvalue ); + } + if ( getDvarInt( dvarstring ) > maxvalue ) + { + setdvar( dvarstring, maxvalue ); + } + else + { + if ( getDvarInt( dvarstring ) < minvalue ) + { + setdvar( dvarstring, minvalue ); + } + } + level.grenadelauncherdudtimedvar = dvarstring; + level.grenadelauncherdudtimemin = minvalue; + level.grenadelauncherdudtimemax = maxvalue; + level.grenadelauncherdudtime = getDvarInt( level.grenadelauncherdudtimedvar ); +} + +registerthrowngrenadeduddvar( dvarstring, defaultvalue, minvalue, maxvalue ) +{ + dvarstring = "scr_" + dvarstring + "_thrownGrenadeDudTime"; + if ( getDvar( dvarstring ) == "" ) + { + setdvar( dvarstring, defaultvalue ); + } + if ( getDvarInt( dvarstring ) > maxvalue ) + { + setdvar( dvarstring, maxvalue ); + } + else + { + if ( getDvarInt( dvarstring ) < minvalue ) + { + setdvar( dvarstring, minvalue ); + } + } + level.throwngrenadedudtimedvar = dvarstring; + level.throwngrenadedudtimemin = minvalue; + level.throwngrenadedudtimemax = maxvalue; + level.throwngrenadedudtime = getDvarInt( level.throwngrenadedudtimedvar ); +} + +registerkillstreakdelay( dvarstring, defaultvalue, minvalue, maxvalue ) +{ + dvarstring = "scr_" + dvarstring + "_killstreakDelayTime"; + if ( getDvar( dvarstring ) == "" ) + { + setdvar( dvarstring, defaultvalue ); + } + if ( getDvarInt( dvarstring ) > maxvalue ) + { + setdvar( dvarstring, maxvalue ); + } + else + { + if ( getDvarInt( dvarstring ) < minvalue ) + { + setdvar( dvarstring, minvalue ); + } + } + level.killstreakrounddelay = getDvarInt( dvarstring ); +} + +turngrenadeintoadud( weapname, isthrowngrenade, player ) +{ + if ( level.grenadelauncherdudtime >= ( maps/mp/gametypes_zm/_globallogic_utils::gettimepassed() / 1000 ) && !isthrowngrenade ) + { + if ( issubstr( weapname, "gl_" ) || weapname == "china_lake_mp" ) + { + timeleft = int( level.grenadelauncherdudtime - ( maps/mp/gametypes_zm/_globallogic_utils::gettimepassed() / 1000 ) ); + if ( !timeleft ) + { + timeleft = 1; + } + player iprintlnbold( &"MP_LAUNCHER_UNAVAILABLE_FOR_N", " " + timeleft + " ", &"EXE_SECONDS" ); + self makegrenadedud(); + } + } + else + { + if ( level.throwngrenadedudtime >= ( maps/mp/gametypes_zm/_globallogic_utils::gettimepassed() / 1000 ) && isthrowngrenade ) + { + if ( weapname == "frag_grenade_mp" || weapname == "sticky_grenade_mp" ) + { + if ( isDefined( player.suicide ) && player.suicide ) + { + return; + } + timeleft = int( level.throwngrenadedudtime - ( maps/mp/gametypes_zm/_globallogic_utils::gettimepassed() / 1000 ) ); + if ( !timeleft ) + { + timeleft = 1; + } + player iprintlnbold( &"MP_GRENADE_UNAVAILABLE_FOR_N", " " + timeleft + " ", &"EXE_SECONDS" ); + self makegrenadedud(); + } + } + } +} + +watchforgrenadeduds() +{ + self endon( "spawned_player" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "grenade_fire", grenade, weapname ); + grenade turngrenadeintoadud( weapname, 1, self ); + } +} + +watchforgrenadelauncherduds() +{ + self endon( "spawned_player" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "grenade_launcher_fire", grenade, weapname ); + grenade turngrenadeintoadud( weapname, 0, self ); + } +} + +getdamageableents( pos, radius, dolos, startradius ) +{ + ents = []; + if ( !isDefined( dolos ) ) + { + dolos = 0; + } + if ( !isDefined( startradius ) ) + { + startradius = 0; + } + players = level.players; + i = 0; + while ( i < players.size ) + { + if ( !isalive( players[ i ] ) || players[ i ].sessionstate != "playing" ) + { + i++; + continue; + } + else + { + playerpos = players[ i ].origin + vectorScale( ( 0, 0, 1 ), 32 ); + distsq = distancesquared( pos, playerpos ); + if ( distsq < ( radius * radius ) || !dolos && weapondamagetracepassed( pos, playerpos, startradius, undefined ) ) + { + newent = spawnstruct(); + newent.isplayer = 1; + newent.isadestructable = 0; + newent.isadestructible = 0; + newent.isactor = 0; + newent.entity = players[ i ]; + newent.damagecenter = playerpos; + ents[ ents.size ] = newent; + } + } + i++; + } + grenades = getentarray( "grenade", "classname" ); + i = 0; + while ( i < grenades.size ) + { + entpos = grenades[ i ].origin; + distsq = distancesquared( pos, entpos ); + if ( distsq < ( radius * radius ) || !dolos && weapondamagetracepassed( pos, entpos, startradius, grenades[ i ] ) ) + { + newent = spawnstruct(); + newent.isplayer = 0; + newent.isadestructable = 0; + newent.isadestructible = 0; + newent.isactor = 0; + newent.entity = grenades[ i ]; + newent.damagecenter = entpos; + ents[ ents.size ] = newent; + } + i++; + } + destructibles = getentarray( "destructible", "targetname" ); + i = 0; + while ( i < destructibles.size ) + { + entpos = destructibles[ i ].origin; + distsq = distancesquared( pos, entpos ); + if ( distsq < ( radius * radius ) || !dolos && weapondamagetracepassed( pos, entpos, startradius, destructibles[ i ] ) ) + { + newent = spawnstruct(); + newent.isplayer = 0; + newent.isadestructable = 0; + newent.isadestructible = 1; + newent.isactor = 0; + newent.entity = destructibles[ i ]; + newent.damagecenter = entpos; + ents[ ents.size ] = newent; + } + i++; + } + destructables = getentarray( "destructable", "targetname" ); + i = 0; + while ( i < destructables.size ) + { + entpos = destructables[ i ].origin; + distsq = distancesquared( pos, entpos ); + if ( distsq < ( radius * radius ) || !dolos && weapondamagetracepassed( pos, entpos, startradius, destructables[ i ] ) ) + { + newent = spawnstruct(); + newent.isplayer = 0; + newent.isadestructable = 1; + newent.isadestructible = 0; + newent.isactor = 0; + newent.entity = destructables[ i ]; + newent.damagecenter = entpos; + ents[ ents.size ] = newent; + } + i++; + } + return ents; +} + +weapondamagetracepassed( from, to, startradius, ignore ) +{ + trace = weapondamagetrace( from, to, startradius, ignore ); + return trace[ "fraction" ] == 1; +} + +weapondamagetrace( from, to, startradius, ignore ) +{ + midpos = undefined; + diff = to - from; + if ( lengthsquared( diff ) < ( startradius * startradius ) ) + { + midpos = to; + } + dir = vectornormalize( diff ); + midpos = from + ( dir[ 0 ] * startradius, dir[ 1 ] * startradius, dir[ 2 ] * startradius ); + trace = bullettrace( midpos, to, 0, ignore ); + if ( getDvarInt( #"0A1C40B1" ) != 0 ) + { + if ( trace[ "fraction" ] == 1 ) + { + thread debugline( midpos, to, ( 0, 0, 1 ) ); + } + else + { + thread debugline( midpos, trace[ "position" ], ( 1, 0,9, 0,8 ) ); + thread debugline( trace[ "position" ], to, ( 1, 0,4, 0,3 ) ); + } + } + return trace; +} + +damageent( einflictor, eattacker, idamage, smeansofdeath, sweapon, damagepos, damagedir ) +{ + if ( self.isplayer ) + { + self.damageorigin = damagepos; + self.entity thread [[ level.callbackplayerdamage ]]( einflictor, eattacker, idamage, 0, smeansofdeath, sweapon, damagepos, damagedir, "none", 0, 0 ); + } + else if ( self.isactor ) + { + self.damageorigin = damagepos; + self.entity thread [[ level.callbackactordamage ]]( einflictor, eattacker, idamage, 0, smeansofdeath, sweapon, damagepos, damagedir, "none", 0, 0 ); + } + else if ( self.isadestructible ) + { + self.damageorigin = damagepos; + self.entity dodamage( idamage, damagepos, eattacker, einflictor, 0, smeansofdeath, 0, sweapon ); + } + else + { + if ( self.isadestructable || sweapon == "claymore_mp" && sweapon == "airstrike_mp" ) + { + return; + } + self.entity damage_notify_wrapper( idamage, eattacker, ( 0, 0, 1 ), ( 0, 0, 1 ), "mod_explosive", "", "" ); + } +} + +debugline( a, b, color ) +{ +/# + i = 0; + while ( i < 600 ) + { + line( a, b, color ); + wait 0,05; + i++; +#/ + } +} + +onweapondamage( eattacker, einflictor, sweapon, meansofdeath, damage ) +{ + self endon( "death" ); + self endon( "disconnect" ); + switch( sweapon ) + { + case "concussion_grenade_mp": + radius = 512; + if ( self == eattacker ) + { + radius *= 0,5; + } + scale = 1 - ( distance( self.origin, einflictor.origin ) / radius ); + if ( scale < 0 ) + { + scale = 0; + } + time = 2 + ( 4 * scale ); + wait 0,05; + if ( self hasperk( "specialty_stunprotection" ) ) + { + time *= 0,1; + } + self thread playconcussionsound( time ); + if ( self mayapplyscreeneffect() ) + { + self shellshock( "concussion_grenade_mp", time, 0 ); + } + self.concussionendtime = getTime() + ( time * 1000 ); + break; + default: + maps/mp/gametypes_zm/_shellshock::shellshockondamage( meansofdeath, damage ); + break; + } +} + +playconcussionsound( duration ) +{ + self endon( "death" ); + self endon( "disconnect" ); + concussionsound = spawn( "script_origin", ( 0, 0, 1 ) ); + concussionsound.origin = self.origin; + concussionsound linkto( self ); + concussionsound thread deleteentonownerdeath( self ); + concussionsound playsound( "" ); + concussionsound playloopsound( "" ); + if ( duration > 0,5 ) + { + wait ( duration - 0,5 ); + } + concussionsound playsound( "" ); + concussionsound stoploopsound( 0,5 ); + wait 0,5; + concussionsound notify( "delete" ); + concussionsound delete(); +} + +deleteentonownerdeath( owner ) +{ + self endon( "delete" ); + owner waittill( "death" ); + self delete(); +} + +monitor_dog_special_grenades() +{ +} + +isprimaryweapon( weaponname ) +{ + return isDefined( level.primary_weapon_array[ weaponname ] ); +} + +issidearm( weaponname ) +{ + return isDefined( level.side_arm_array[ weaponname ] ); +} + +isinventory( weaponname ) +{ + return isDefined( level.inventory_array[ weaponname ] ); +} + +isgrenade( weaponname ) +{ + return isDefined( level.grenade_array[ weaponname ] ); +} + +isexplosivebulletweapon( weaponname ) +{ + if ( weaponname != "chopper_minigun_mp" && weaponname != "cobra_20mm_mp" || weaponname == "littlebird_guard_minigun_mp" && weaponname == "cobra_20mm_comlink_mp" ) + { + return 1; + } + return 0; +} + +getweaponclass_array( current ) +{ + if ( isprimaryweapon( current ) ) + { + return level.primary_weapon_array; + } + else + { + if ( issidearm( current ) ) + { + return level.side_arm_array; + } + else + { + if ( isgrenade( current ) ) + { + return level.grenade_array; + } + else + { + return level.inventory_array; + } + } + } +} + +updatestowedweapon() +{ + self endon( "spawned" ); + self endon( "killed_player" ); + self endon( "disconnect" ); + self.tag_stowed_back = undefined; + self.tag_stowed_hip = undefined; + team = self.pers[ "team" ]; + class = self.pers[ "class" ]; + while ( 1 ) + { + self waittill( "weapon_change", newweapon ); + self.weapon_array_primary = []; + self.weapon_array_sidearm = []; + self.weapon_array_grenade = []; + self.weapon_array_inventory = []; + weaponslist = self getweaponslist(); + idx = 0; + while ( idx < weaponslist.size ) + { + switch( weaponslist[ idx ] ) + { + case "m202_flash_mp": + case "m220_tow_mp": + case "m32_mp": + case "minigun_mp": + case "mp40_blinged_mp": + case "zipline_mp": + idx++; + continue; + default: + } + if ( isprimaryweapon( weaponslist[ idx ] ) ) + { + self.weapon_array_primary[ self.weapon_array_primary.size ] = weaponslist[ idx ]; + idx++; + continue; + } + else if ( issidearm( weaponslist[ idx ] ) ) + { + self.weapon_array_sidearm[ self.weapon_array_sidearm.size ] = weaponslist[ idx ]; + idx++; + continue; + } + else if ( isgrenade( weaponslist[ idx ] ) ) + { + self.weapon_array_grenade[ self.weapon_array_grenade.size ] = weaponslist[ idx ]; + idx++; + continue; + } + else if ( isinventory( weaponslist[ idx ] ) ) + { + self.weapon_array_inventory[ self.weapon_array_inventory.size ] = weaponslist[ idx ]; + idx++; + continue; + } + else + { + if ( isweaponprimary( weaponslist[ idx ] ) ) + { + self.weapon_array_primary[ self.weapon_array_primary.size ] = weaponslist[ idx ]; + } + } + idx++; + } + detach_all_weapons(); + stow_on_back(); + stow_on_hip(); + } + } + } +} + +forcestowedweaponupdate() +{ + detach_all_weapons(); + stow_on_back(); + stow_on_hip(); +} + +detachcarryobjectmodel() +{ + if ( isDefined( self.carryobject ) && isDefined( self.carryobject maps/mp/gametypes_zm/_gameobjects::getvisiblecarriermodel() ) ) + { + if ( isDefined( self.tag_stowed_back ) ) + { + self detach( self.tag_stowed_back, "tag_stowed_back" ); + self.tag_stowed_back = undefined; + } + } +} + +detach_all_weapons() +{ + if ( isDefined( self.tag_stowed_back ) ) + { + clear_weapon = 1; + if ( isDefined( self.carryobject ) ) + { + carriermodel = self.carryobject maps/mp/gametypes_zm/_gameobjects::getvisiblecarriermodel(); + if ( isDefined( carriermodel ) && carriermodel == self.tag_stowed_back ) + { + self detach( self.tag_stowed_back, "tag_stowed_back" ); + clear_weapon = 0; + } + } + if ( clear_weapon ) + { + self clearstowedweapon(); + } + self.tag_stowed_back = undefined; + } + if ( isDefined( self.tag_stowed_hip ) ) + { + detach_model = getweaponmodel( self.tag_stowed_hip ); + self detach( detach_model, "tag_stowed_hip_rear" ); + self.tag_stowed_hip = undefined; + } +} + +non_stowed_weapon( weapon ) +{ + if ( self hasweapon( "knife_ballistic_mp" ) && weapon != "knife_ballistic_mp" ) + { + return 1; + } + if ( self hasweapon( "knife_held_mp" ) && weapon != "knife_held_mp" ) + { + return 1; + } + return 0; +} + +stow_on_back( current ) +{ + current = self getcurrentweapon(); + self.tag_stowed_back = undefined; + weaponoptions = 0; + index_weapon = ""; + if ( isDefined( self.carryobject ) && isDefined( self.carryobject maps/mp/gametypes_zm/_gameobjects::getvisiblecarriermodel() ) ) + { + self.tag_stowed_back = self.carryobject maps/mp/gametypes_zm/_gameobjects::getvisiblecarriermodel(); + self attach( self.tag_stowed_back, "tag_stowed_back", 1 ); + return; + } + else + { + if ( non_stowed_weapon( current ) || self.hasriotshield ) + { + return; + } + else + { + idx = 0; + while ( idx < self.weapon_array_primary.size ) + { + temp_index_weapon = self.weapon_array_primary[ idx ]; +/# + assert( isDefined( temp_index_weapon ), "Primary weapon list corrupted." ); +#/ + if ( temp_index_weapon == current ) + { + idx++; + continue; + } + else if ( current == "none" ) + { + idx++; + continue; + } + else if ( !issubstr( current, "gl_" ) && !issubstr( temp_index_weapon, "gl_" ) && !issubstr( current, "mk_" ) && !issubstr( temp_index_weapon, "mk_" ) && !issubstr( current, "dualoptic_" ) && !issubstr( temp_index_weapon, "dualoptic_" ) || issubstr( current, "ft_" ) && issubstr( temp_index_weapon, "ft_" ) ) + { + index_weapon_tok = strtok( temp_index_weapon, "_" ); + current_tok = strtok( current, "_" ); + i = 0; + while ( i < index_weapon_tok.size ) + { + if ( !issubstr( current, index_weapon_tok[ i ] ) || index_weapon_tok.size != current_tok.size ) + { + i = 0; + break; + } + else + { + i++; + } + } + if ( i == index_weapon_tok.size ) + { + idx++; + continue; + } + } + else + { + index_weapon = temp_index_weapon; +/# + assert( isDefined( self.curclass ), "Player missing current class" ); +#/ + if ( issubstr( index_weapon, self.pers[ "primaryWeapon" ] ) && issubstr( self.curclass, "CUSTOM" ) ) + { + self.tag_stowed_back = getweaponmodel( index_weapon, self getloadoutitem( self.class_num, "primarycamo" ) ); + } + else + { + stowedmodelindex = getweaponstowedmodel( index_weapon ); + self.tag_stowed_back = getweaponmodel( index_weapon, stowedmodelindex ); + } + if ( issubstr( self.curclass, "CUSTOM" ) ) + { + weaponoptions = self calcweaponoptions( self.class_num, 0 ); + } + } + idx++; + } + } + } + if ( !isDefined( self.tag_stowed_back ) ) + { + return; + } + self setstowedweapon( index_weapon ); +} + +stow_on_hip() +{ + current = self getcurrentweapon(); + self.tag_stowed_hip = undefined; + idx = 0; + while ( idx < self.weapon_array_inventory.size ) + { + if ( self.weapon_array_inventory[ idx ] == current ) + { + idx++; + continue; + } + else if ( !self getweaponammostock( self.weapon_array_inventory[ idx ] ) ) + { + idx++; + continue; + } + else + { + self.tag_stowed_hip = self.weapon_array_inventory[ idx ]; + } + idx++; + } + if ( !isDefined( self.tag_stowed_hip ) ) + { + return; + } + if ( self.tag_stowed_hip != "satchel_charge_mp" || self.tag_stowed_hip == "claymore_mp" && self.tag_stowed_hip == "bouncingbetty_mp" ) + { + self.tag_stowed_hip = undefined; + return; + } + weapon_model = getweaponmodel( self.tag_stowed_hip ); + self attach( weapon_model, "tag_stowed_hip_rear", 1 ); +} + +stow_inventory( inventories, current ) +{ + if ( isDefined( self.inventory_tag ) ) + { + detach_model = getweaponmodel( self.inventory_tag ); + self detach( detach_model, "tag_stowed_hip_rear" ); + self.inventory_tag = undefined; + } + if ( !isDefined( inventories[ 0 ] ) || self getweaponammostock( inventories[ 0 ] ) == 0 ) + { + return; + } + if ( inventories[ 0 ] != current ) + { + self.inventory_tag = inventories[ 0 ]; + weapon_model = getweaponmodel( self.inventory_tag ); + self attach( weapon_model, "tag_stowed_hip_rear", 1 ); + } +} + +weapons_get_dvar_int( dvar, def ) +{ + return int( weapons_get_dvar( dvar, def ) ); +} + +weapons_get_dvar( dvar, def ) +{ + if ( getDvar( dvar ) != "" ) + { + return getDvarFloat( dvar ); + } + else + { + setdvar( dvar, def ); + return def; + } +} + +player_is_driver() +{ + if ( !isalive( self ) ) + { + return 0; + } + if ( self isremotecontrolling() ) + { + return 0; + } + vehicle = self getvehicleoccupied(); + if ( isDefined( vehicle ) ) + { + seat = vehicle getoccupantseat( self ); + if ( isDefined( seat ) && seat == 0 ) + { + return 1; + } + } + return 0; +} + +loadout_get_class_num() +{ +/# + assert( isplayer( self ) ); +#/ +/# + assert( isDefined( self.class ) ); +#/ + if ( isDefined( level.classtoclassnum[ self.class ] ) ) + { + return level.classtoclassnum[ self.class ]; + } + class_num = int( self.class[ self.class.size - 1 ] ) - 1; + if ( class_num == -1 ) + { + class_num = 9; + } + return class_num; +} + +loadout_get_offhand_weapon( stat ) +{ + if ( isDefined( level.givecustomloadout ) ) + { + return "weapon_null_mp"; + } + class_num = self loadout_get_class_num(); + index = 0; + if ( isDefined( level.tbl_weaponids[ index ] ) && isDefined( level.tbl_weaponids[ index ][ "reference" ] ) ) + { + return level.tbl_weaponids[ index ][ "reference" ] + "_mp"; + } + return "weapon_null_mp"; +} + +loadout_get_offhand_count( stat ) +{ + if ( isDefined( level.givecustomloadout ) ) + { + return 0; + } + class_num = self loadout_get_class_num(); + count = 0; + return count; +} + +scavenger_think() +{ + self endon( "death" ); + self waittill( "scavenger", player ); + primary_weapons = player getweaponslistprimaries(); + offhand_weapons_and_alts = array_exclude( player getweaponslist( 1 ), primary_weapons ); + arrayremovevalue( offhand_weapons_and_alts, "knife_mp" ); + player playsound( "fly_equipment_pickup_npc" ); + player playlocalsound( "fly_equipment_pickup_plr" ); + player.scavenger_icon.alpha = 1; + player.scavenger_icon fadeovertime( 2,5 ); + player.scavenger_icon.alpha = 0; + scavenger_lethal_proc = 1; + scavenger_tactical_proc = 1; + if ( !isDefined( player.scavenger_lethal_proc ) ) + { + player.scavenger_lethal_proc = 0; + player.scavenger_tactical_proc = 0; + } + loadout_primary = player loadout_get_offhand_weapon( "primarygrenade" ); + loadout_primary_count = player loadout_get_offhand_count( "primarygrenadecount" ); + loadout_secondary = player loadout_get_offhand_weapon( "specialgrenade" ); + loadout_secondary_count = player loadout_get_offhand_count( "specialgrenadeCount" ); + i = 0; + while ( i < offhand_weapons_and_alts.size ) + { + weapon = offhand_weapons_and_alts[ i ]; + if ( ishackweapon( weapon ) ) + { + break; + i++; + continue; + } + else switch( weapon ) + { + case "bouncingbetty_mp": + case "claymore_mp": + case "frag_grenade_mp": + case "hatchet_mp": + case "satchel_charge_mp": + case "sticky_grenade_mp": + if ( isDefined( player.grenadetypeprimarycount ) && player.grenadetypeprimarycount < 1 ) + { + break; + i++; + continue; + } + else + { + if ( player getweaponammostock( weapon ) != loadout_primary_count ) + { + if ( player.scavenger_lethal_proc < scavenger_lethal_proc ) + { + player.scavenger_lethal_proc++; + break; + i++; + continue; + } + else player.scavenger_lethal_proc = 0; + player.scavenger_tactical_proc = 0; + } + case "concussion_grenade_mp": + case "emp_grenade_mp": + case "flash_grenade_mp": + case "nightingale_mp": + case "pda_hack_mp": + case "proximity_grenade_mp": + case "sensor_grenade_mp": + case "tabun_gas_mp": + case "trophy_system_mp": + case "willy_pete_mp": + if ( isDefined( player.grenadetypesecondarycount ) && player.grenadetypesecondarycount < 1 ) + { + break; + i++; + continue; + } + else + { + if ( weapon == loadout_secondary && player getweaponammostock( weapon ) != loadout_secondary_count ) + { + if ( player.scavenger_tactical_proc < scavenger_tactical_proc ) + { + player.scavenger_tactical_proc++; + break; + i++; + continue; + } + else player.scavenger_tactical_proc = 0; + player.scavenger_lethal_proc = 0; + } + maxammo = weaponmaxammo( weapon ); + stock = player getweaponammostock( weapon ); + if ( isDefined( level.customloadoutscavenge ) ) + { + maxammo = self [[ level.customloadoutscavenge ]]( weapon ); + } + else if ( weapon == loadout_primary ) + { + maxammo = loadout_primary_count; + } + else + { + if ( weapon == loadout_secondary ) + { + maxammo = loadout_secondary_count; + } + } + if ( stock < maxammo ) + { + ammo = stock + 1; + if ( ammo > maxammo ) + { + ammo = maxammo; + } + player setweaponammostock( weapon, ammo ); + player thread maps/mp/_challenges::scavengedgrenade(); + } + break; + i++; + continue; + default: + if ( islauncherweapon( weapon ) ) + { + stock = player getweaponammostock( weapon ); + start = player getfractionstartammo( weapon ); + clip = weaponclipsize( weapon ); + clip *= getdvarfloatdefault( "scavenger_clip_multiplier", 2 ); + clip = int( clip ); + maxammo = weaponmaxammo( weapon ); + if ( stock < ( maxammo - clip ) ) + { + ammo = stock + clip; + player setweaponammostock( weapon, ammo ); + break; + } + else + { + player setweaponammostock( weapon, maxammo ); + } + } + break; + i++; + continue; +} +} +} +i++; +} +i = 0; +while ( i < primary_weapons.size ) +{ +weapon = primary_weapons[ i ]; +if ( ishackweapon( weapon ) || weapon == "kniferang_mp" ) +{ +i++; +continue; +} +else +{ +stock = player getweaponammostock( weapon ); +start = player getfractionstartammo( weapon ); +clip = weaponclipsize( weapon ); +clip *= getdvarfloatdefault( "scavenger_clip_multiplier", 2 ); +clip = int( clip ); +maxammo = weaponmaxammo( weapon ); +if ( stock < ( maxammo - clip ) ) +{ +ammo = stock + clip; +player setweaponammostock( weapon, ammo ); +i++; +continue; +} +else +{ +player setweaponammostock( weapon, maxammo ); +} +} +i++; +} +} + +scavenger_hud_create() +{ + if ( level.wagermatch ) + { + return; + } + self.scavenger_icon = newclienthudelem( self ); + self.scavenger_icon.horzalign = "center"; + self.scavenger_icon.vertalign = "middle"; + self.scavenger_icon.x = -16; + self.scavenger_icon.y = 16; + self.scavenger_icon.alpha = 0; + width = 32; + height = 16; + if ( self issplitscreen() ) + { + width = int( width * 0,5 ); + height = int( height * 0,5 ); + self.scavenger_icon.x = -8; + } + self.scavenger_icon setshader( "hud_scavenger_pickup", width, height ); +} + +dropscavengerfordeath( attacker ) +{ + if ( sessionmodeiszombiesgame() ) + { + return; + } + if ( level.wagermatch ) + { + return; + } + if ( !isDefined( attacker ) ) + { + return; + } + if ( attacker == self ) + { + return; + } + if ( level.gametype == "hack" ) + { + item = self dropscavengeritem( "scavenger_item_hack_mp" ); + } + else + { + item = self dropscavengeritem( "scavenger_item_mp" ); + } + item thread scavenger_think(); +} + +addlimitedweapon( weapon_name, owner, num_drops ) +{ + limited_info = spawnstruct(); + limited_info.weapon = weapon_name; + limited_info.drops = num_drops; + owner.limited_info = limited_info; +} + +shoulddroplimitedweapon( weapon_name, owner ) +{ + limited_info = owner.limited_info; + if ( !isDefined( limited_info ) ) + { + return 1; + } + if ( limited_info.weapon != weapon_name ) + { + return 1; + } + if ( limited_info.drops <= 0 ) + { + return 0; + } + return 1; +} + +droplimitedweapon( weapon_name, owner, item ) +{ + limited_info = owner.limited_info; + if ( !isDefined( limited_info ) ) + { + return; + } + if ( limited_info.weapon != weapon_name ) + { + return; + } + limited_info.drops -= 1; + owner.limited_info = undefined; + item thread limitedpickup( limited_info ); +} + +limitedpickup( limited_info ) +{ + self endon( "death" ); + self waittill( "trigger", player, item ); + if ( !isDefined( item ) ) + { + return; + } + player.limited_info = limited_info; +}