diff --git a/patch_mp/maps/mp/gametypes/_battlechatter_mp.gsc b/patch_mp/maps/mp/gametypes/_battlechatter_mp.gsc new file mode 100644 index 0000000..77acc4e --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_battlechatter_mp.gsc @@ -0,0 +1,1213 @@ +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_globallogic; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + if ( level.createfx_enabled ) + { + return; + } + _a10 = level.teams; + _k10 = getFirstArrayKey( _a10 ); + while ( isDefined( _k10 ) ) + { + team = _a10[ _k10 ]; +/# + assert( isDefined( level.teamprefix[ team ] ) ); +#/ +/# + assert( isDefined( level.teamprefix[ team ] ) ); +#/ + level.isteamspeaking[ team ] = 0; + level.speakers[ team ] = []; + _k10 = getNextArrayKey( _a10, _k10 ); + } + level.bcsounds = []; + level.bcsounds[ "inform_attack" ] = "attack"; + level.bcsounds[ "c4_out" ] = "c4"; + level.bcsounds[ "claymore_out" ] = "claymore"; + level.bcsounds[ "emp_out" ] = "emp"; + level.bcsounds[ "flash_out" ] = "flash"; + level.bcsounds[ "gas_out" ] = "gas"; + level.bcsounds[ "frag_out" ] = "grenade"; + level.bcsounds[ "revive_out" ] = "revive"; + level.bcsounds[ "smoke_out" ] = "smoke"; + level.bcsounds[ "sticky_out" ] = "sticky"; + level.bcsounds[ "gas_incoming" ] = "gas"; + level.bcsounds[ "grenade_incoming" ] = "incoming"; + level.bcsounds[ "kill" ] = "kill"; + level.bcsounds[ "kill_sniper" ] = "kill_sniper"; + level.bcsounds[ "revive" ] = "need_revive"; + level.bcsounds[ "reload" ] = "reloading"; + level.bcsounds[ "enemy" ] = "threat"; + level.bcsounds[ "sniper" ] = "sniper"; + level.bcsounds[ "conc_out" ] = "attack_stun"; + level.bcsounds[ "satchel_plant" ] = "attack_throwsatchel"; + level.bcsounds[ "casualty" ] = "casualty_gen"; + level.bcsounds[ "flare_out" ] = "attack_flare"; + level.bcsounds[ "betty_plant" ] = "plant"; + level.bcsounds[ "landmark" ] = "landmark"; + level.bcsounds[ "taunt" ] = "taunt"; + level.bcsounds[ "killstreak_enemy" ] = "enemy"; + level.bcsounds[ "killstreak_taunt" ] = "kls"; + level.bcsounds[ "kill_killstreak" ] = "killstreak"; + level.bcsounds[ "destructible" ] = "destructible_near"; + level.bcsounds[ "teammate" ] = "teammate_near"; + level.bcsounds[ "gametype" ] = "gametype"; + level.bcsounds[ "squad" ] = "squad"; + level.bcsounds[ "gametype" ] = "gametype"; + level.bcsounds[ "perk" ] = "perk_equip"; + level.bcsounds[ "pain" ] = "pain"; + level.bcsounds[ "death" ] = "death"; + level.bcsounds[ "breathing" ] = "breathing"; + level.bcsounds[ "inform_need" ] = "need"; + level.bcsounds[ "scream" ] = "scream"; + level.bcsounds[ "fire" ] = "fire"; + setdvar( "bcmp_weapon_delay", "2000" ); + setdvar( "bcmp_weapon_fire_probability", "80" ); + setdvar( "bcmp_weapon_reload_probability", "60" ); + setdvar( "bcmp_weapon_fire_threat_probability", "80" ); + setdvar( "bcmp_sniper_kill_probability", "20" ); + setdvar( "bcmp_ally_kill_probability", "60" ); + setdvar( "bcmp_killstreak_incoming_probability", "100" ); + setdvar( "bcmp_perk_call_probability", "100" ); + setdvar( "bcmp_incoming_grenade_probability", "5" ); + setdvar( "bcmp_toss_grenade_probability", "20" ); + setdvar( "bcmp_toss_trophy_probability", "80" ); + setdvar( "bcmp_kill_inform_probability", "40" ); + setdvar( "bcmp_pain_small_probability", "0" ); + setdvar( "bcmp_breathing_probability", "0" ); + setdvar( "bcmp_pain_delay", ".5" ); + setdvar( "bcmp_last_stand_delay", "3" ); + setdvar( "bcmp_breathing_delay", "" ); + setdvar( "bcmp_enemy_contact_delay", "30" ); + setdvar( "bcmp_enemy_contact_level_delay", "15" ); + level.bcweapondelay = getDvarInt( "bcmp_weapon_delay" ); + level.bcweaponfireprobability = getDvarInt( "bcmp_weapon_fire_probability" ); + level.bcweaponreloadprobability = getDvarInt( "bcmp_weapon_reload_probability" ); + level.bcweaponfirethreatprobability = getDvarInt( "bcmp_weapon_fire_threat_probability" ); + level.bcsniperkillprobability = getDvarInt( "bcmp_sniper_kill_probability" ); + level.bcallykillprobability = getDvarInt( "bcmp_ally_kill_probability" ); + level.bckillstreakincomingprobability = getDvarInt( "bcmp_killstreak_incoming_probability" ); + level.bcperkcallprobability = getDvarInt( "bcmp_perk_call_probability" ); + level.bcincominggrenadeprobability = getDvarInt( "bcmp_incoming_grenade_probability" ); + level.bctossgrenadeprobability = getDvarInt( "bcmp_toss_grenade_probability" ); + level.bctosstrophyprobability = getDvarInt( "bcmp_toss_trophy_probability" ); + level.bckillinformprobability = getDvarInt( "bcmp_kill_inform_probability" ); + level.bcpainsmallprobability = getDvarInt( "bcmp_pain_small_probability" ); + level.bcpaindelay = getDvarInt( "bcmp_pain_delay" ); + level.bclaststanddelay = getDvarInt( "bcmp_last_stand_delay" ); + level.bcmp_breathing_delay = getDvarInt( "bcmp_breathing_delay" ); + level.bcmp_enemy_contact_delay = getDvarInt( "bcmp_enemy_contact_delay" ); + level.bcmp_enemy_contact_level_delay = getDvarInt( "bcmp_enemy_contact_level_delay" ); + level.bcmp_breathing_probability = getDvarInt( "bcmp_breathing_probability" ); + level.allowbattlechatter = getgametypesetting( "allowBattleChatter" ); + level.landmarks = getentarray( "trigger_landmark", "targetname" ); + level.enemyspotteddialog = 1; + level thread enemycontactleveldelay(); + level thread onplayerconnect(); + level thread updatebcdvars(); + level.battlechatter_init = 1; +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onjoinedteam(); + player thread onplayerspawned(); + } +} + +updatebcdvars() +{ + level endon( "game_ended" ); + for ( ;; ) + { + level.bcweapondelay = getDvarInt( "bcmp_weapon_delay" ); + level.bckillinformprobability = getDvarInt( "bcmp_kill_inform_probability" ); + level.bcweaponfireprobability = getDvarInt( "bcmp_weapon_fire_probability" ); + level.bcsniperkillprobability = getDvarInt( "bcmp_sniper_kill_probability" ); + level thread maps/mp/gametypes/_globallogic::updateteamstatus(); + wait 2; + } +} + +onjoinedteam() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_team" ); + self.pers[ "bcVoiceNumber" ] = randomintrange( 0, 3 ); + self.pilotisspeaking = 0; + } +} + +onjoinedspectators() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_spectators" ); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self.lastbcattempttime = 0; + self.heartbeatsnd = 0; + self.soundmod = "player"; + self.bcvoicenumber = self.pers[ "bcVoiceNumber" ]; + self.pilotisspeaking = 0; + if ( level.splitscreen ) + { + continue; + } + else + { + self thread reloadtracking(); + self thread grenadetracking(); + self thread enemythreat(); + self thread stickygrenadetracking(); + self thread painvox(); + self thread allyrevive(); + self thread onfirescream(); + self thread deathvox(); + self thread watchmissileusage(); + } + } +} + +enemycontactleveldelay() +{ + while ( 1 ) + { + level waittill( "level_enemy_spotted" ); + level.enemyspotteddialog = 0; + wait level.bcmp_enemy_contact_level_delay; + level.enemyspotteddialog = 1; + } +} + +breathinghurtvox() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + for ( ;; ) + { + self waittill( "snd_breathing_hurt" ); + if ( randomintrange( 0, 100 ) >= level.bcmp_breathing_probability ) + { + wait 0,5; + if ( isalive( self ) ) + { + level thread mpsaylocalsound( self, "breathing", "hurt", 0, 1 ); + } + } + wait level.bcmp_breathing_delay; + } +} + +onfirescream() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "snd_burn_scream" ); + if ( randomintrange( 0, 100 ) >= level.bcmp_breathing_probability ) + { + wait 0,5; + if ( isalive( self ) ) + { + level thread mpsaylocalsound( self, "fire", "scream" ); + } + } + wait level.bcmp_breathing_delay; + } +} + +breathingbettervox() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + for ( ;; ) + { + self waittill( "snd_breathing_better" ); + if ( isalive( self ) ) + { + level thread mpsaylocalsound( self, "breathing", "better", 0, 1 ); + } + } +} + +laststandvox() +{ + self endon( "death" ); + self endon( "disconnect" ); + self waittill( "snd_last_stand" ); + for ( ;; ) + { + self waittill( "weapon_fired" ); + if ( isalive( self ) ) + { + level thread mpsaylocalsound( self, "perk", "laststand" ); + } + wait level.bclaststanddelay; + } +} + +allyrevive() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "snd_ally_revive" ); + if ( isalive( self ) ) + { + level thread mpsaylocalsound( self, "inform_attack", "revive" ); + } + wait level.bclaststanddelay; + } +} + +painvox() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "snd_pain_player" ); + if ( randomintrange( 0, 100 ) >= level.bcpainsmallprobability ) + { + if ( isalive( self ) ) + { + soundalias = level.teamprefix[ self.team ] + self.bcvoicenumber + "_" + level.bcsounds[ "pain" ] + "_" + "small"; + self thread dosound( soundalias ); + } + } + wait level.bcpaindelay; + } +} + +deathvox() +{ + self endon( "disconnect" ); + self waittill( "death" ); + if ( self.team != "spectator" ) + { + soundalias = level.teamprefix[ self.team ] + self.bcvoicenumber + "_" + level.bcsounds[ "pain" ] + "_" + "death"; + self thread dosound( soundalias ); + } +} + +stickygrenadetracking() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "sticky_explode" ); + for ( ;; ) + { + self waittill( "grenade_stuck", grenade ); + if ( isDefined( grenade ) ) + { + grenade.stucktoplayer = self; + } + if ( isalive( self ) ) + { + level thread mpsaylocalsound( self, "grenade_incoming", "sticky" ); + } + self notify( "sticky_explode" ); + } +} + +onplayersuicideorteamkill( player, type ) +{ + self endon( "disconnect" ); + waittillframeend; + if ( !isDefined( level.battlechatter_init ) ) + { + return; + } + if ( !level.teambased ) + { + return; + } + myteam = player.team; + if ( isDefined( level.aliveplayers[ myteam ] ) ) + { + if ( level.aliveplayers[ myteam ].size ) + { + index = checkdistancetoevent( player, 1000000 ); + if ( isDefined( index ) ) + { + wait 1; + if ( isalive( level.aliveplayers[ myteam ][ index ] ) ) + { + level thread mpsaylocalsound( level.aliveplayers[ myteam ][ index ], "teammate", type ); + } + } + } + } +} + +onplayerkillstreak( player ) +{ + player endon( "disconnect" ); +} + +onkillstreakused( killstreak, team ) +{ +} + +onplayernearexplodable( object, type ) +{ + self endon( "disconnect" ); + self endon( "explosion_started" ); +} + +shoeboxtracking() +{ + self endon( "death" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "begin_firing" ); + weaponname = self getcurrentweapon(); + if ( weaponname == "mine_shoebox_mp" ) + { + level thread mpsaylocalsound( self, "satchel_plant", "shoebox" ); + } + } +} + +checkweaponreload( weapon ) +{ + switch( weapon ) + { + case "crossbow_mp": + case "fhj18_mp": + case "judge_mp": + case "smaw_mp": + case "usrpg_mp": + return 0; + default: + return 1; + } +} + +reloadtracking() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "reload_start" ); + if ( randomintrange( 0, 100 ) >= level.bcweaponreloadprobability ) + { + weaponname = self getcurrentweapon(); + weaponshouldreload = checkweaponreload( weaponname ); + if ( weaponshouldreload ) + { + level thread mpsaylocalsound( self, "reload", "gen" ); + } + } + } +} + +perkspecificbattlechatter( type, checkdistance ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "perk_done" ); +} + +enemythreat() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "weapon_fired" ); + if ( level.enemyspotteddialog ) + { + if ( ( getTime() - self.lastbcattempttime ) > level.bcmp_enemy_contact_delay ) + { + shooter = self; + myteam = self.team; + closest_enemy = shooter get_closest_player_enemy(); + self.lastbcattempttime = getTime(); + if ( isDefined( closest_enemy ) ) + { + if ( randomintrange( 0, 100 ) >= level.bcweaponfirethreatprobability ) + { + area = 360000; + if ( distancesquared( closest_enemy.origin, self.origin ) < area ) + { + level thread mpsaylocalsound( closest_enemy, "enemy", "infantry", 0 ); + level notify( "level_enemy_spotted" ); + } + } + } + } + } + } +} + +weaponfired() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "weapon_fired" ); + while ( ( getTime() - self.lastbcattempttime ) > level.bcweapondelay ) + { + self.lastbcattempttime = getTime(); + while ( randomintrange( 0, 100 ) >= level.bcweaponfireprobability ) + { + self.landmarkent = self getlandmark(); + while ( isDefined( self.landmarkent ) ) + { + myteam = self.team; + _a646 = level.teams; + _k646 = getFirstArrayKey( _a646 ); + while ( isDefined( _k646 ) ) + { + team = _a646[ _k646 ]; + if ( team == myteam ) + { + } + else + { + keys = getarraykeys( level.squads[ team ] ); + i = 0; + while ( i < keys.size ) + { + if ( level.squads[ team ][ keys[ i ] ].size ) + { + index = randomintrange( 0, level.squads[ team ][ keys[ i ] ].size ); + level thread mpsaylocalsound( level.squads[ team ][ keys[ i ] ][ index ], "enemy", "infantry" ); + } + i++; + } + } + _k646 = getNextArrayKey( _a646, _k646 ); + } + } + } + } + } +} + +killedbysniper( sniper ) +{ + self endon( "disconnect" ); + sniper endon( "disconnect" ); + waittillframeend; + if ( !isDefined( level.battlechatter_init ) ) + { + return; + } + victim = self; + if ( level.hardcoremode || !level.teambased ) + { + return; + } + sniper.issniperspotted = 1; + if ( randomintrange( 0, 100 ) >= level.bcsniperkillprobability ) + { + sniperteam = sniper.team; + victimteam = self.team; + index = checkdistancetoevent( victim, 1000000 ); + if ( isDefined( index ) ) + { + level thread mpsaylocalsound( level.aliveplayers[ victimteam ][ index ], "enemy", "sniper", 0 ); + } + } +} + +playerkilled( attacker ) +{ + self endon( "disconnect" ); + if ( !isplayer( attacker ) ) + { + return; + } + waittillframeend; + if ( !isDefined( level.battlechatter_init ) ) + { + return; + } + victim = self; + if ( level.hardcoremode ) + { + return; + } + if ( randomintrange( 0, 100 ) >= level.bcallykillprobability ) + { + attackerteam = attacker.team; + victimteam = self.team; + closest_ally = victim get_closest_player_ally(); + area = 1000000; + if ( isDefined( closest_ally ) ) + { + if ( distancesquared( closest_ally.origin, self.origin ) < area ) + { + level thread mpsaylocalsound( closest_ally, "inform_attack", "revive", 0 ); + } + } + } +} + +grenadetracking() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "grenade_fire", grenade, weaponname ); + if ( weaponname == "frag_grenade_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "grenade" ); + } + level thread incominggrenadetracking( self, grenade, "grenade" ); + continue; + } + else if ( weaponname == "satchel_charge_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "c4" ); + } + continue; + } + else if ( weaponname == "emp_grenade_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "emp" ); + } + continue; + } + else if ( weaponname == "claymore_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "claymore" ); + } + continue; + } + else if ( weaponname == "flash_grenade_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "flash" ); + } + continue; + } + else if ( weaponname == "sticky_grenade_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "sticky" ); + } + continue; + } + else if ( weaponname == "tabun_gas_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "gas" ); + } + continue; + } + else if ( weaponname == "willy_pete_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "smoke" ); + } + continue; + } + else if ( weaponname == "hatchet_mp" || weaponname == "proximity_grenade_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "hatchet" ); + } + continue; + } + else + { + if ( weaponname == "concussion_grenade_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "concussion" ); + } + break; + } + else if ( weaponname == "scrambler_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "scrambler" ); + } + break; + } + else if ( weaponname == "tactical_insertion_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "tactical" ); + } + break; + } + else if ( weaponname == "bouncingbetty_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctosstrophyprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "c4" ); + } + break; + } + else if ( weaponname == "sensor_grenade_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctossgrenadeprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "hatchet" ); + } + break; + } + else + { + if ( weaponname == "trophy_system_mp" ) + { + if ( randomintrange( 0, 100 ) >= level.bctosstrophyprobability ) + { + level thread mpsaylocalsound( self, "inform_attack", "scrambler" ); + } + } + } + } + } +} + +watchmissileusage() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + for ( ;; ) + { + self waittill( "missile_fire", missile, weapon_name ); + if ( weapon_name == "usrpg_mp" ) + { + level thread incominggrenadetracking( self, missile, "rpg", 0,2 ); + continue; + } + else + { + return; + } + } +} + +incominggrenadetracking( thrower, grenade, type, waittime ) +{ + if ( randomintrange( 0, 100 ) >= level.bcincominggrenadeprobability ) + { + if ( !isDefined( waittime ) ) + { + waittime = 1; + } + wait waittime; + if ( !isDefined( thrower ) ) + { + return; + } + if ( thrower.team == "spectator" ) + { + return; + } + enemyteam = thrower.team; + if ( level.players.size ) + { + player = checkdistancetoobject( 250000, grenade, enemyteam, thrower ); + if ( isDefined( player ) ) + { + level thread mpsaylocalsound( player, "grenade_incoming", type ); + } + } + } +} + +incomingspecialgrenadetracking( type ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "grenade_ended" ); + for ( ;; ) + { + if ( randomintrange( 0, 100 ) >= level.bcincominggrenadeprobability ) + { + if ( level.aliveplayers[ self.team ].size || !level.teambased && level.players.size ) + { + level thread mpsaylocalsound( self, "grenade_incoming", type ); + self notify( "grenade_ended" ); + } + } + wait 3; + } +} + +gametypespecificbattlechatter( event, team ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "event_ended" ); + for ( ;; ) + { + if ( isDefined( team ) ) + { + index = checkdistancetoevent( self, 90000 ); + if ( isDefined( index ) ) + { + level thread mpsaylocalsound( level.aliveplayers[ team ][ index ], "gametype", event ); + self notify( "event_ended" ); + } + } + else + { + _a939 = level.teams; + _k939 = getFirstArrayKey( _a939 ); + while ( isDefined( _k939 ) ) + { + team = _a939[ _k939 ]; + index = randomintrange( 0, level.aliveplayers[ team ].size ); + level thread mpsaylocalsound( level.aliveplayers[ team ][ index ], "gametype", event ); + _k939 = getNextArrayKey( _a939, _k939 ); + } + } + wait 1; + } +} + +checkweaponkill( weapon ) +{ + switch( weapon ) + { + case "cobra_20mm_comlink_mp": + case "knife_mp": + return 1; + default: + return 0; + } +} + +saykillbattlechatter( attacker, sweapon, victim ) +{ + if ( checkweaponkill( sweapon ) ) + { + return; + } + if ( isDefined( victim.issniperspotted ) && victim.issniperspotted && randomintrange( 0, 100 ) >= level.bckillinformprobability ) + { + level thread saylocalsounddelayed( attacker, "kill", "sniper", 0,75 ); + victim.issniperspotted = 0; + } + else + { + if ( isDefined( level.bckillinformprobability ) && randomintrange( 0, 100 ) >= level.bckillinformprobability ) + { + if ( !maps/mp/killstreaks/_killstreaks::iskillstreakweapon( sweapon ) ) + { + level thread saylocalsounddelayed( attacker, "kill", "infantry", 0,75 ); + } + } + } +} + +saylocalsounddelayed( player, soundtype1, soundtype2, delay ) +{ + player endon( "death" ); + player endon( "disconnect" ); + if ( !isDefined( level.battlechatter_init ) ) + { + return; + } + wait delay; + mpsaylocalsound( player, soundtype1, soundtype2 ); +} + +saylocalsound( player, soundtype ) +{ + player endon( "death" ); + player endon( "disconnect" ); + if ( isspeakerinrange( player ) ) + { + return; + } + if ( player.team != "spectator" ) + { + soundalias = level.teamprefix[ player.team ] + player.bcvoicenumber + "_" + level.bcsounds[ soundtype ]; + } +} + +mpsaylocalsound( player, partone, parttwo, checkspeakers, is2d ) +{ + player endon( "death" ); + player endon( "disconnect" ); + if ( level.players.size <= 1 ) + { + return; + } + if ( !isDefined( checkspeakers ) ) + { + if ( isspeakerinrange( player ) ) + { + return; + } + } + if ( player hasperk( "specialty_quieter" ) ) + { + return; + } + if ( player.team != "spectator" ) + { + soundalias = level.teamprefix[ player.team ] + player.bcvoicenumber + "_" + level.bcsounds[ partone ] + "_" + parttwo; + if ( isDefined( is2d ) ) + { + player thread dosound( soundalias, is2d ); + return; + } + else + { + player thread dosound( soundalias ); + } + } +} + +mpsaylocationallocalsound( player, prefix, partone, parttwo ) +{ + player endon( "death" ); + player endon( "disconnect" ); + if ( level.players.size <= 1 ) + { + return; + } + if ( isspeakerinrange( player ) ) + { + return; + } + if ( player.team != "spectator" ) + { + soundalias1 = level.teamprefix[ player.team ] + player.bcvoicenumber + "_" + level.bcsounds[ prefix ]; + soundalias2 = level.teamprefix[ player.team ] + player.bcvoicenumber + "_" + level.bcsounds[ partone ] + "_" + parttwo; + player thread dolocationalsound( soundalias1, soundalias2 ); + } +} + +dosound( soundalias, is2d ) +{ + team = self.team; + level addspeaker( self, team ); + if ( isDefined( is2d ) ) + { + self playlocalsound( soundalias ); + } + else + { + if ( level.allowbattlechatter && level.teambased ) + { + self playsoundontag( soundalias, "J_Head" ); + } + } + self thread waitplaybacktime( soundalias ); + self waittill_any( soundalias, "death", "disconnect" ); + level removespeaker( self, team ); +} + +dolocationalsound( soundalias1, soundalias2 ) +{ + team = self.team; + level addspeaker( self, team ); + if ( level.allowbattlechatter && level.teambased ) + { + self playbattlechattertoteam( soundalias1, soundalias2, team, self ); + } + self thread waitplaybacktime( soundalias1 ); + self waittill_any( soundalias1, "death", "disconnect" ); + level removespeaker( self, team ); +} + +waitplaybacktime( soundalias ) +{ + self endon( "death" ); + self endon( "disconnect" ); + playbacktime = soundgetplaybacktime( soundalias ); + if ( playbacktime >= 0 ) + { + waittime = playbacktime * 0,001; + wait waittime; + } + else + { + wait 1; + } + self notify( soundalias ); +} + +isspeakerinrange( player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + distsq = 1000000; + while ( isDefined( player ) && isDefined( player.team ) && player.team != "spectator" ) + { + index = 0; + while ( index < level.speakers[ player.team ].size ) + { + teammate = level.speakers[ player.team ][ index ]; + if ( teammate == player ) + { + return 1; + } + if ( distancesquared( teammate.origin, player.origin ) < distsq ) + { + return 1; + } + index++; + } + } + return 0; +} + +addspeaker( player, team ) +{ + level.speakers[ team ][ level.speakers[ team ].size ] = player; +} + +removespeaker( player, team ) +{ + newspeakers = []; + index = 0; + while ( index < level.speakers[ team ].size ) + { + if ( level.speakers[ team ][ index ] == player ) + { + index++; + continue; + } + else + { + newspeakers[ newspeakers.size ] = level.speakers[ team ][ index ]; + } + index++; + } + level.speakers[ team ] = newspeakers; +} + +getlandmark() +{ + landmarks = level.landmarks; + i = 0; + while ( i < landmarks.size ) + { + if ( self istouching( landmarks[ i ] ) && isDefined( landmarks[ i ].script_landmark ) ) + { + return landmarks[ i ]; + } + i++; + } + return undefined; +} + +checkdistancetoevent( player, area ) +{ + if ( !isDefined( player ) ) + { + return undefined; + } + index = 0; + while ( index < level.aliveplayers[ player.team ].size ) + { + teammate = level.aliveplayers[ player.team ][ index ]; + if ( !isDefined( teammate ) ) + { + index++; + continue; + } + else if ( teammate == player ) + { + index++; + continue; + } + else + { + if ( distancesquared( teammate.origin, player.origin ) < area ) + { + return index; + } + } + index++; + } +} + +checkdistancetoenemy( enemy, area, team ) +{ + if ( !isDefined( enemy ) ) + { + return undefined; + } + index = 0; + while ( index < level.aliveplayers[ team ].size ) + { + player = level.aliveplayers[ team ][ index ]; + if ( distancesquared( enemy.origin, player.origin ) < area ) + { + return index; + } + index++; + } +} + +checkdistancetoobject( area, object, ignoreteam, ignoreent ) +{ + if ( isDefined( ignoreteam ) ) + { + _a1232 = level.teams; + _k1232 = getFirstArrayKey( _a1232 ); + while ( isDefined( _k1232 ) ) + { + team = _a1232[ _k1232 ]; + i = 0; + while ( i < level.aliveplayers[ team ].size ) + { + player = level.aliveplayers[ team ][ i ]; + if ( isDefined( ignoreent ) && player == ignoreent ) + { + i++; + continue; + } + else + { + if ( isDefined( object ) && distancesquared( player.origin, object.origin ) < area ) + { + return player; + } + } + i++; + } + _k1232 = getNextArrayKey( _a1232, _k1232 ); + } + } + else i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isDefined( ignoreent ) && player == ignoreent ) + { + i++; + continue; + } + else + { + if ( isalive( player ) ) + { + if ( isDefined( object ) && distancesquared( player.origin, object.origin ) < area ) + { + return player; + } + } + } + i++; + } +} + +get_closest_player_enemy() +{ + players = getplayers(); + players = arraysort( players, self.origin ); + _a1269 = players; + _k1269 = getFirstArrayKey( _a1269 ); + while ( isDefined( _k1269 ) ) + { + player = _a1269[ _k1269 ]; + if ( !isDefined( player ) || !isalive( player ) ) + { + } + else + { + if ( player.sessionstate != "playing" ) + { + break; + } + else if ( player == self ) + { + break; + } + else if ( level.teambased && self.team == player.team ) + { + break; + } + else + { + return player; + } + } + _k1269 = getNextArrayKey( _a1269, _k1269 ); + } + return undefined; +} + +get_closest_player_ally() +{ + if ( !level.teambased ) + { + return undefined; + } + players = getplayers( self.team ); + players = arraysort( players, self.origin ); + _a1307 = players; + _k1307 = getFirstArrayKey( _a1307 ); + while ( isDefined( _k1307 ) ) + { + player = _a1307[ _k1307 ]; + if ( !isDefined( player ) || !isalive( player ) ) + { + } + else + { + if ( player.sessionstate != "playing" ) + { + break; + } + else if ( player == self ) + { + break; + } + else + { + return player; + } + } + _k1307 = getNextArrayKey( _a1307, _k1307 ); + } + return undefined; +} diff --git a/patch_mp/maps/mp/gametypes/_callbacksetup.gsc b/patch_mp/maps/mp/gametypes/_callbacksetup.gsc new file mode 100644 index 0000000..b96ee03 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_class.gsc b/patch_mp/maps/mp/gametypes/_class.gsc new file mode 100644 index 0000000..b22d67f --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_class.gsc @@ -0,0 +1,1315 @@ +#include maps/mp/_challenges; +#include maps/mp/gametypes/_dev; +#include maps/mp/teams/_teams; +#include maps/mp/gametypes/_class; +#include maps/mp/killstreaks/_killstreak_weapons; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_tweakables; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + level.classmap[ "class_smg" ] = "CLASS_SMG"; + level.classmap[ "class_cqb" ] = "CLASS_CQB"; + level.classmap[ "class_assault" ] = "CLASS_ASSAULT"; + level.classmap[ "class_lmg" ] = "CLASS_LMG"; + level.classmap[ "class_sniper" ] = "CLASS_SNIPER"; + level.classmap[ "custom0" ] = "CLASS_CUSTOM1"; + level.classmap[ "custom1" ] = "CLASS_CUSTOM2"; + level.classmap[ "custom2" ] = "CLASS_CUSTOM3"; + level.classmap[ "custom3" ] = "CLASS_CUSTOM4"; + level.classmap[ "custom4" ] = "CLASS_CUSTOM5"; + level.classmap[ "custom5" ] = "CLASS_CUSTOM6"; + level.classmap[ "custom6" ] = "CLASS_CUSTOM7"; + level.classmap[ "custom7" ] = "CLASS_CUSTOM8"; + level.classmap[ "custom8" ] = "CLASS_CUSTOM9"; + level.classmap[ "custom9" ] = "CLASS_CUSTOM10"; + level.maxkillstreaks = 4; + level.maxspecialties = 6; + level.maxbonuscards = 3; + level.maxallocation = getgametypesetting( "maxAllocation" ); + level.loadoutkillstreaksenabled = getgametypesetting( "loadoutKillstreaksEnabled" ); + level.prestigenumber = 5; + level.defaultclass = "CLASS_ASSAULT"; + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "weapon", "allowfrag" ) ) + { + level.weapons[ "frag" ] = "frag_grenade_mp"; + } + else + { + level.weapons[ "frag" ] = ""; + } + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "weapon", "allowsmoke" ) ) + { + level.weapons[ "smoke" ] = "smoke_grenade_mp"; + } + else + { + level.weapons[ "smoke" ] = ""; + } + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "weapon", "allowflash" ) ) + { + level.weapons[ "flash" ] = "flash_grenade_mp"; + } + else + { + level.weapons[ "flash" ] = ""; + } + level.weapons[ "concussion" ] = "concussion_grenade_mp"; + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "weapon", "allowsatchel" ) ) + { + level.weapons[ "satchel_charge" ] = "satchel_charge_mp"; + } + else + { + level.weapons[ "satchel_charge" ] = ""; + } + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "weapon", "allowbetty" ) ) + { + level.weapons[ "betty" ] = "mine_bouncing_betty_mp"; + } + else + { + level.weapons[ "betty" ] = ""; + } + if ( maps/mp/gametypes/_tweakables::gettweakablevalue( "weapon", "allowrpgs" ) ) + { + level.weapons[ "rpg" ] = "rpg_mp"; + } + else + { + level.weapons[ "rpg" ] = ""; + } + create_class_exclusion_list(); + cac_init(); + load_default_loadout( "CLASS_SMG", 10 ); + load_default_loadout( "CLASS_CQB", 11 ); + load_default_loadout( "CLASS_ASSAULT", 12 ); + load_default_loadout( "CLASS_LMG", 13 ); + load_default_loadout( "CLASS_SNIPER", 14 ); + level.primary_weapon_array = []; + level.side_arm_array = []; + level.grenade_array = []; + level.inventory_array = []; + max_weapon_num = 99; + i = 0; + while ( i < max_weapon_num ) + { + if ( !isDefined( level.tbl_weaponids[ i ] ) || level.tbl_weaponids[ i ][ "group" ] == "" ) + { + i++; + continue; + } + else + { + if ( !isDefined( level.tbl_weaponids[ i ] ) || level.tbl_weaponids[ i ][ "reference" ] == "" ) + { + i++; + continue; + } + else + { + weapon_type = level.tbl_weaponids[ i ][ "group" ]; + weapon = level.tbl_weaponids[ i ][ "reference" ]; + attachment = level.tbl_weaponids[ i ][ "attachment" ]; + weapon_class_register( weapon + "_mp", weapon_type ); + while ( isDefined( attachment ) && attachment != "" ) + { + attachment_tokens = strtok( attachment, " " ); + while ( isDefined( attachment_tokens ) ) + { + if ( attachment_tokens.size == 0 ) + { + weapon_class_register( ( weapon + "_" ) + attachment + "_mp", weapon_type ); + i++; + continue; + } + else + { + k = 0; + while ( k < attachment_tokens.size ) + { + weapon_class_register( ( weapon + "_" ) + attachment_tokens[ k ] + "_mp", weapon_type ); + k++; + } + } + } + } + } + } + i++; + } + precacheshader( "waypoint_second_chance" ); + level thread onplayerconnecting(); +} + +create_class_exclusion_list() +{ + currentdvar = 0; + level.itemexclusions = []; + while ( getDvarInt( 853497292 + currentdvar ) ) + { + level.itemexclusions[ currentdvar ] = getDvarInt( 853497292 + currentdvar ); + currentdvar++; + } + level.attachmentexclusions = []; + currentdvar = 0; + while ( getDvar( 2137981926 + currentdvar ) != "" ) + { + level.attachmentexclusions[ currentdvar ] = getDvar( 2137981926 + currentdvar ); + currentdvar++; + } +} + +is_item_excluded( itemindex ) +{ + if ( !level.onlinegame ) + { + return 0; + } + numexclusions = level.itemexclusions.size; + exclusionindex = 0; + while ( exclusionindex < numexclusions ) + { + if ( itemindex == level.itemexclusions[ exclusionindex ] ) + { + return 1; + } + exclusionindex++; + } + return 0; +} + +is_attachment_excluded( attachment ) +{ + numexclusions = level.attachmentexclusions.size; + exclusionindex = 0; + while ( exclusionindex < numexclusions ) + { + if ( attachment == level.attachmentexclusions[ exclusionindex ] ) + { + return 1; + } + exclusionindex++; + } + return 0; +} + +set_statstable_id() +{ + if ( !isDefined( level.statstableid ) ) + { + level.statstableid = tablelookupfindcoreasset( "mp/statsTable.csv" ); + } +} + +get_item_count( itemreference ) +{ + set_statstable_id(); + itemcount = int( tablelookup( level.statstableid, 4, itemreference, 5 ) ); + if ( itemcount < 1 ) + { + itemcount = 1; + } + return itemcount; +} + +getdefaultclassslotwithexclusions( classname, slotname ) +{ + itemreference = getdefaultclassslot( classname, slotname ); + set_statstable_id(); + itemindex = int( tablelookup( level.statstableid, 4, itemreference, 0 ) ); + if ( is_item_excluded( itemindex ) ) + { + itemreference = tablelookup( level.statstableid, 0, 0, 4 ); + } + return itemreference; +} + +load_default_loadout( class, classnum ) +{ + level.classtoclassnum[ class ] = classnum; +} + +weapon_class_register( weapon, weapon_type ) +{ + if ( issubstr( "weapon_smg weapon_cqb weapon_assault weapon_lmg weapon_sniper weapon_shotgun weapon_launcher weapon_special", weapon_type ) ) + { + level.primary_weapon_array[ weapon ] = 1; + } + else if ( issubstr( "weapon_pistol", weapon_type ) ) + { + level.side_arm_array[ weapon ] = 1; + } + else if ( weapon_type == "weapon_grenade" ) + { + level.grenade_array[ weapon ] = 1; + } + else if ( weapon_type == "weapon_explosive" ) + { + level.inventory_array[ weapon ] = 1; + } + else if ( weapon_type == "weapon_rifle" ) + { + level.inventory_array[ weapon ] = 1; + } + else + { +/# + assert( 0, "Weapon group info is missing from statsTable for: " + weapon_type ); +#/ + } +} + +cac_init() +{ + level.tbl_weaponids = []; + set_statstable_id(); + i = 0; + while ( i < 256 ) + { + itemrow = tablelookuprownum( level.statstableid, 0, i ); + if ( itemrow > -1 ) + { + group_s = tablelookupcolumnforrow( level.statstableid, itemrow, 2 ); + if ( issubstr( group_s, "weapon_" ) ) + { + reference_s = tablelookupcolumnforrow( level.statstableid, itemrow, 4 ); + if ( reference_s != "" ) + { + level.tbl_weaponids[ i ][ "reference" ] = reference_s; + level.tbl_weaponids[ i ][ "group" ] = group_s; + level.tbl_weaponids[ i ][ "count" ] = int( tablelookupcolumnforrow( level.statstableid, itemrow, 5 ) ); + level.tbl_weaponids[ i ][ "attachment" ] = tablelookupcolumnforrow( level.statstableid, itemrow, 8 ); + } + } + } + i++; + } + level.perknames = []; + i = 0; + while ( i < 256 ) + { + itemrow = tablelookuprownum( level.statstableid, 0, i ); + if ( itemrow > -1 ) + { + group_s = tablelookupcolumnforrow( level.statstableid, itemrow, 2 ); + if ( group_s == "specialty" ) + { + reference_s = tablelookupcolumnforrow( level.statstableid, itemrow, 4 ); + if ( reference_s != "" ) + { + perkicon = tablelookupcolumnforrow( level.statstableid, itemrow, 6 ); + perkname = tablelookupistring( level.statstableid, 0, i, 3 ); + precachestring( perkname ); + precacheshader( perkicon ); + level.perknames[ perkicon ] = perkname; + } + } + } + i++; + } + level.killstreaknames = []; + level.killstreakicons = []; + level.killstreakindices = []; + i = 0; + while ( i < 256 ) + { + itemrow = tablelookuprownum( level.statstableid, 0, i ); + if ( itemrow > -1 ) + { + group_s = tablelookupcolumnforrow( level.statstableid, itemrow, 2 ); + if ( group_s == "killstreak" ) + { + reference_s = tablelookupcolumnforrow( level.statstableid, itemrow, 4 ); + if ( reference_s != "" ) + { + level.tbl_killstreakdata[ i ] = reference_s; + level.killstreakindices[ reference_s ] = i; + icon = tablelookupcolumnforrow( level.statstableid, itemrow, 6 ); + name = tablelookupistring( level.statstableid, 0, i, 3 ); + precachestring( name ); + level.killstreaknames[ reference_s ] = name; + level.killstreakicons[ reference_s ] = icon; + level.killstreakindices[ reference_s ] = i; + precacheshader( icon ); + precacheshader( icon + "_drop" ); + } + } + } + i++; + } +} + +getclasschoice( response ) +{ +/# + assert( isDefined( level.classmap[ response ] ) ); +#/ + return level.classmap[ response ]; +} + +getloadoutitemfromddlstats( customclassnum, loadoutslot ) +{ + itemindex = self getloadoutitem( customclassnum, loadoutslot ); + if ( is_item_excluded( itemindex ) && !is_warlord_perk( itemindex ) ) + { + return 0; + } + return itemindex; +} + +getattachmentstring( weaponnum, attachmentnum ) +{ + attachmentstring = getitemattachment( weaponnum, attachmentnum ); + if ( attachmentstring != "none" && !is_attachment_excluded( attachmentstring ) ) + { + attachmentstring += "_"; + } + else + { + attachmentstring = ""; + } + return attachmentstring; +} + +getattachmentsdisabled() +{ + if ( !isDefined( level.attachmentsdisabled ) ) + { + return 0; + } + return level.attachmentsdisabled; +} + +getkillstreakindex( class, killstreaknum ) +{ + killstreaknum++; + killstreakstring = "killstreak" + killstreaknum; + if ( getDvarInt( #"826EB3B9" ) == 2 ) + { + return getDvarInt( 3788714527 + killstreakstring ); + } + else + { + return self getloadoutitem( class, killstreakstring ); + } +} + +givekillstreaks( classnum ) +{ + self.killstreak = []; + if ( !level.loadoutkillstreaksenabled ) + { + return; + } + sortedkillstreaks = []; + currentkillstreak = 0; + killstreaknum = 0; + while ( killstreaknum < level.maxkillstreaks ) + { + killstreakindex = getkillstreakindex( classnum, killstreaknum ); + if ( isDefined( killstreakindex ) && killstreakindex > 0 ) + { +/# + assert( isDefined( level.tbl_killstreakdata[ killstreakindex ] ), "KillStreak #:" + killstreakindex + "'s data is undefined" ); +#/ + if ( isDefined( level.tbl_killstreakdata[ killstreakindex ] ) ) + { + self.killstreak[ currentkillstreak ] = level.tbl_killstreakdata[ killstreakindex ]; + if ( isDefined( level.usingmomentum ) && level.usingmomentum ) + { + killstreaktype = maps/mp/killstreaks/_killstreaks::getkillstreakbymenuname( self.killstreak[ currentkillstreak ] ); + if ( isDefined( killstreaktype ) ) + { + weapon = maps/mp/killstreaks/_killstreaks::getkillstreakweapon( killstreaktype ); + self giveweapon( weapon ); + if ( isDefined( level.usingscorestreaks ) && level.usingscorestreaks ) + { + if ( maps/mp/killstreaks/_killstreak_weapons::isheldkillstreakweapon( weapon ) ) + { + if ( !isDefined( self.pers[ "held_killstreak_ammo_count" ][ weapon ] ) ) + { + self.pers[ "held_killstreak_ammo_count" ][ weapon ] = 0; + } + if ( !isDefined( self.pers[ "held_killstreak_clip_count" ][ weapon ] ) ) + { + self.pers[ "held_killstreak_clip_count" ][ weapon ] = 0; + } + if ( self.pers[ "held_killstreak_ammo_count" ][ weapon ] > 0 ) + { + self setweaponammoclip( weapon, self.pers[ "held_killstreak_clip_count" ][ weapon ] ); + self setweaponammostock( weapon, self.pers[ "held_killstreak_ammo_count" ][ weapon ] - self.pers[ "held_killstreak_clip_count" ][ weapon ] ); + } + else + { + self maps/mp/gametypes/_class::setweaponammooverall( weapon, 0 ); + } + break; + } + else + { + quantity = self.pers[ "killstreak_quantity" ][ weapon ]; + if ( !isDefined( quantity ) ) + { + quantity = 0; + } + self setweaponammoclip( weapon, quantity ); + } + } + sortdata = spawnstruct(); + sortdata.cost = level.killstreaks[ killstreaktype ].momentumcost; + sortdata.weapon = weapon; + sortindex = 0; + sortindex = 0; + while ( sortindex < sortedkillstreaks.size ) + { + if ( sortedkillstreaks[ sortindex ].cost > sortdata.cost ) + { + break; + } + else + { + sortindex++; + } + } + i = sortedkillstreaks.size; + while ( i > sortindex ) + { + sortedkillstreaks[ i ] = sortedkillstreaks[ i - 1 ]; + i--; + + } + sortedkillstreaks[ sortindex ] = sortdata; + } + } + currentkillstreak++; + } + } + killstreaknum++; + } + actionslotorder = []; + actionslotorder[ 0 ] = 4; + actionslotorder[ 1 ] = 2; + actionslotorder[ 2 ] = 1; + while ( isDefined( level.usingmomentum ) && level.usingmomentum ) + { + sortindex = 0; + while ( sortindex < sortedkillstreaks.size && sortindex < actionslotorder.size ) + { + self setactionslot( actionslotorder[ sortindex ], "weapon", sortedkillstreaks[ sortindex ].weapon ); + sortindex++; + } + } +} + +is_warlord_perk( itemindex ) +{ + if ( itemindex == 168 || itemindex == 169 ) + { + return 1; + } + else + { + return 0; + } +} + +isperkgroup( perkname ) +{ + if ( isDefined( perkname ) ) + { + return isstring( perkname ); + } +} + +logclasschoice( class, primaryweapon, specialtype, perks ) +{ + if ( class == self.lastclass ) + { + return; + } + self logstring( "choseclass: " + class + " weapon: " + primaryweapon + " special: " + specialtype ); + i = 0; + while ( i < perks.size ) + { + self logstring( "perk" + i + ": " + perks[ i ] ); + i++; + } + self.lastclass = class; +} + +reset_specialty_slots( class_num ) +{ + self.specialty = []; +} + +initstaticweaponstime() +{ + self.staticweaponsstarttime = getTime(); +} + +initweaponattachments( weaponname ) +{ + self.currentweaponstarttime = getTime(); + self.currentweapon = weaponname; +} + +isequipmentallowed( equipment ) +{ + if ( equipment == "camera_spike_mp" && self issplitscreen() ) + { + return 0; + } + if ( equipment == level.tacticalinsertionweapon && level.disabletacinsert ) + { + return 0; + } + return 1; +} + +isleagueitemrestricted( item ) +{ + if ( level.leaguematch ) + { + return isitemrestricted( item ); + } + return 0; +} + +giveloadoutlevelspecific( team, class ) +{ + pixbeginevent( "giveLoadoutLevelSpecific" ); + if ( isDefined( level.givecustomcharacters ) ) + { + self [[ level.givecustomcharacters ]](); + } + if ( isDefined( level.givecustomloadout ) ) + { + self [[ level.givecustomloadout ]](); + } + pixendevent(); +} + +removeduplicateattachments( weapon ) +{ + if ( !isDefined( weapon ) ) + { + return undefined; + } + attachments = strtok( weapon, "+" ); + attachmentindex = 1; + while ( attachmentindex < attachments.size ) + { + attachmentindex2 = attachmentindex + 1; + while ( attachmentindex2 < attachments.size ) + { + if ( attachments[ attachmentindex ] == attachments[ attachmentindex2 ] ) + { + attachments[ attachmentindex2 ] = "none"; + } + attachmentindex2++; + } + attachmentindex++; + } + uniqueattachmentsweapon = attachments[ 0 ]; + attachmentindex = 1; + while ( attachmentindex < attachments.size ) + { + if ( attachments[ attachmentindex ] != "none" ) + { + uniqueattachmentsweapon = ( uniqueattachmentsweapon + "+" ) + attachments[ attachmentindex ]; + } + attachmentindex++; + } + return uniqueattachmentsweapon; +} + +giveloadout( team, class ) +{ + pixbeginevent( "giveLoadout" ); + self takeallweapons(); + primaryindex = 0; + self.specialty = []; + self.killstreak = []; + primaryweapon = undefined; + self notify( "give_map" ); + class_num_for_killstreaks = 0; + primaryweaponoptions = 0; + secondaryweaponoptions = 0; + playerrenderoptions = 0; + primarygrenadecount = 0; + iscustomclass = 0; + if ( issubstr( class, "CLASS_CUSTOM" ) ) + { + pixbeginevent( "custom class" ); + class_num = int( class[ class.size - 1 ] ) - 1; + if ( class_num == -1 ) + { + class_num = 9; + } + self.class_num = class_num; + self reset_specialty_slots( class_num ); + playerrenderoptions = self calcplayeroptions( class_num ); + class_num_for_killstreaks = class_num; + iscustomclass = 1; + pixendevent(); + } + else + { + pixbeginevent( "default class" ); +/# + assert( isDefined( self.pers[ "class" ] ), "Player during spawn and loadout got no class!" ); +#/ + class_num = level.classtoclassnum[ class ]; + self.class_num = class_num; + pixendevent(); + } + knifeweaponoptions = self calcweaponoptions( class_num, 2 ); + self giveweapon( "knife_mp", 0, knifeweaponoptions ); + self.specialty = self getloadoutperks( class_num ); + while ( level.leaguematch ) + { + i = 0; + while ( i < self.specialty.size ) + { + if ( isleagueitemrestricted( self.specialty[ i ] ) ) + { + arrayremoveindex( self.specialty, i ); + i--; + + } + i++; + } + } + self register_perks(); + self setactionslot( 3, "altMode" ); + self setactionslot( 4, "" ); + givekillstreaks( class_num_for_killstreaks ); + spawnweapon = ""; + initialweaponcount = 0; + if ( isDefined( self.pers[ "weapon" ] ) && self.pers[ "weapon" ] != "none" && !maps/mp/killstreaks/_killstreaks::iskillstreakweapon( self.pers[ "weapon" ] ) ) + { + weapon = self.pers[ "weapon" ]; + } + else + { + weapon = self getloadoutweapon( class_num, "primary" ); + weapon = removeduplicateattachments( weapon ); + if ( maps/mp/killstreaks/_killstreaks::iskillstreakweapon( weapon ) ) + { + weapon = "weapon_null_mp"; + } + } + sidearm = self getloadoutweapon( class_num, "secondary" ); + sidearm = removeduplicateattachments( sidearm ); + if ( maps/mp/killstreaks/_killstreaks::iskillstreakweapon( sidearm ) ) + { + sidearm = "weapon_null_mp"; + } + self.primaryweaponkill = 0; + self.secondaryweaponkill = 0; + if ( self isbonuscardactive( 2, self.class_num ) ) + { + self.primaryloadoutweapon = weapon; + self.primaryloadoutaltweapon = weaponaltweaponname( weapon ); + self.secondaryloadoutweapon = sidearm; + self.secondaryloadoutaltweapon = weaponaltweaponname( sidearm ); + } + else + { + if ( self isbonuscardactive( 0, self.class_num ) ) + { + self.primaryloadoutweapon = weapon; + } + if ( self isbonuscardactive( 1, self.class_num ) ) + { + self.secondaryloadoutweapon = sidearm; + } + } + if ( sidearm != "weapon_null_mp" ) + { + secondaryweaponoptions = self calcweaponoptions( class_num, 1 ); + } + primaryweapon = weapon; + if ( primaryweapon != "weapon_null_mp" ) + { + primaryweaponoptions = self calcweaponoptions( class_num, 0 ); + } + if ( sidearm != "" && sidearm != "weapon_null_mp" && sidearm != "weapon_null" ) + { + self giveweapon( sidearm, 0, secondaryweaponoptions ); + if ( self hasperk( "specialty_extraammo" ) ) + { + self givemaxammo( sidearm ); + } + spawnweapon = sidearm; + initialweaponcount++; + } + primaryweapon = weapon; + primarytokens = strtok( primaryweapon, "_" ); + self.pers[ "primaryWeapon" ] = primarytokens[ 0 ]; +/# + println( "^5GiveWeapon( " + weapon + " ) -- weapon" ); +#/ + if ( primaryweapon != "" && primaryweapon != "weapon_null_mp" && primaryweapon != "weapon_null" ) + { + if ( self hasperk( "specialty_extraammo" ) ) + { + self givemaxammo( primaryweapon ); + } + self giveweapon( primaryweapon, 0, primaryweaponoptions ); + spawnweapon = primaryweapon; + initialweaponcount++; + } + if ( initialweaponcount < 2 ) + { + self giveweapon( "knife_held_mp", 0, knifeweaponoptions ); + if ( initialweaponcount == 0 ) + { + spawnweapon = "knife_held_mp"; + } + } + if ( !isDefined( self.spawnweapon ) && isDefined( self.pers[ "spawnWeapon" ] ) ) + { + self.spawnweapon = self.pers[ "spawnWeapon" ]; + } + if ( isDefined( self.spawnweapon ) && doesweaponreplacespawnweapon( self.spawnweapon, spawnweapon ) && !self.pers[ "changed_class" ] ) + { + spawnweapon = self.spawnweapon; + } + self.pers[ "changed_class" ] = 0; +/# + assert( spawnweapon != "" ); +#/ + self.spawnweapon = spawnweapon; + self.pers[ "spawnWeapon" ] = self.spawnweapon; + self setspawnweapon( spawnweapon ); + grenadetypeprimary = self getloadoutitemref( class_num, "primarygrenade" ); + if ( isleagueitemrestricted( grenadetypeprimary ) ) + { + grenadetypeprimary = ""; + } + if ( maps/mp/killstreaks/_killstreaks::iskillstreakweapon( grenadetypeprimary + "_mp" ) ) + { + grenadetypeprimary = ""; + } + grenadetypesecondary = self getloadoutitemref( class_num, "specialgrenade" ); + if ( isleagueitemrestricted( grenadetypesecondary ) ) + { + grenadetypesecondary = ""; + } + if ( maps/mp/killstreaks/_killstreaks::iskillstreakweapon( grenadetypesecondary + "_mp" ) ) + { + grenadetypesecondary = ""; + } + if ( grenadetypeprimary != "" && grenadetypeprimary != "weapon_null_mp" && isequipmentallowed( grenadetypeprimary ) ) + { + grenadetypeprimary += "_mp"; + primarygrenadecount = self getloadoutitem( class_num, "primarygrenadecount" ); + } + if ( grenadetypesecondary != "" && grenadetypesecondary != "weapon_null_mp" && isequipmentallowed( grenadetypesecondary ) ) + { + grenadetypesecondary += "_mp"; + grenadesecondarycount = self getloadoutitem( class_num, "specialgrenadecount" ); + } + if ( grenadetypeprimary != "" && grenadetypeprimary != "weapon_null_mp" && !isequipmentallowed( grenadetypeprimary ) ) + { + if ( grenadetypesecondary != level.weapons[ "frag" ] ) + { + grenadetypeprimary = level.weapons[ "frag" ]; + } + else + { + grenadetypeprimary = level.weapons[ "flash" ]; + } + } +/# + println( "^5GiveWeapon( " + grenadetypeprimary + " ) -- grenadeTypePrimary" ); +#/ + self giveweapon( grenadetypeprimary ); + self setweaponammoclip( grenadetypeprimary, primarygrenadecount ); + self switchtooffhand( grenadetypeprimary ); + self.grenadetypeprimary = grenadetypeprimary; + self.grenadetypeprimarycount = primarygrenadecount; + if ( self.grenadetypeprimarycount > 1 ) + { + self dualgrenadesactive(); + } + if ( grenadetypesecondary != "" && grenadetypesecondary != "weapon_null_mp" && isequipmentallowed( grenadetypesecondary ) ) + { + self setoffhandsecondaryclass( grenadetypesecondary ); +/# + println( "^5GiveWeapon( " + grenadetypesecondary + " ) -- grenadeTypeSecondary" ); +#/ + self giveweapon( grenadetypesecondary ); + self setweaponammoclip( grenadetypesecondary, grenadesecondarycount ); + self.grenadetypesecondary = grenadetypesecondary; + self.grenadetypesecondarycount = grenadesecondarycount; + } + self bbclasschoice( class_num, primaryweapon, sidearm ); + if ( !sessionmodeiszombiesgame() ) + { + i = 0; + while ( i < 3 ) + { + if ( level.loadoutkillstreaksenabled && isDefined( self.killstreak[ i ] ) && isDefined( level.killstreakindices[ self.killstreak[ i ] ] ) ) + { + killstreaks[ i ] = level.killstreakindices[ self.killstreak[ i ] ]; + i++; + continue; + } + else + { + killstreaks[ i ] = 0; + } + i++; + } + self recordloadoutperksandkillstreaks( primaryweapon, sidearm, grenadetypeprimary, grenadetypesecondary, killstreaks[ 0 ], killstreaks[ 1 ], killstreaks[ 2 ] ); + } + self maps/mp/teams/_teams::set_player_model( team, weapon ); + self initstaticweaponstime(); + self thread initweaponattachments( spawnweapon ); + self setplayerrenderoptions( playerrenderoptions ); + if ( isDefined( self.movementspeedmodifier ) ) + { + self setmovespeedscale( self.movementspeedmodifier * self getmovespeedscale() ); + } + if ( isDefined( level.givecustomloadout ) ) + { + spawnweapon = self [[ level.givecustomloadout ]](); + if ( isDefined( spawnweapon ) ) + { + self thread initweaponattachments( spawnweapon ); + } + } + self cac_selector(); + if ( !isDefined( self.firstspawn ) ) + { + if ( isDefined( spawnweapon ) ) + { + self initialweaponraise( spawnweapon ); + } + else + { + self initialweaponraise( weapon ); + } + } + else + { + self seteverhadweaponall( 1 ); + } + self.firstspawn = 0; + pixendevent(); +} + +setweaponammooverall( weaponname, amount ) +{ + if ( isweaponcliponly( weaponname ) ) + { + self setweaponammoclip( weaponname, amount ); + } + else + { + self setweaponammoclip( weaponname, amount ); + diff = amount - self getweaponammoclip( weaponname ); +/# + assert( diff >= 0 ); +#/ + self setweaponammostock( weaponname, diff ); + } +} + +onplayerconnecting() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + if ( !level.oldschool ) + { + if ( !isDefined( player.pers[ "class" ] ) ) + { + player.pers[ "class" ] = ""; + } + player.class = player.pers[ "class" ]; + player.lastclass = ""; + } + player.detectexplosives = 0; + player.bombsquadicons = []; + player.bombsquadids = []; + player.reviveicons = []; + player.reviveids = []; + } +} + +fadeaway( waitdelay, fadedelay ) +{ + wait waitdelay; + self fadeovertime( fadedelay ); + self.alpha = 0; +} + +setclass( newclass ) +{ + self.curclass = newclass; +} + +initperkdvars() +{ + level.cac_armorpiercing_data = cac_get_dvar_int( "perk_armorpiercing", "40" ) / 100; + level.cac_bulletdamage_data = cac_get_dvar_int( "perk_bulletDamage", "35" ); + level.cac_fireproof_data = cac_get_dvar_int( "perk_fireproof", "95" ); + level.cac_armorvest_data = cac_get_dvar_int( "perk_armorVest", "80" ); + level.cac_explosivedamage_data = cac_get_dvar_int( "perk_explosiveDamage", "25" ); + level.cac_flakjacket_data = cac_get_dvar_int( "perk_flakJacket", "35" ); + level.cac_flakjacket_hardcore_data = cac_get_dvar_int( "perk_flakJacket_hardcore", "9" ); +} + +cac_selector() +{ + perks = self.specialty; + self.detectexplosives = 0; + i = 0; + while ( i < perks.size ) + { + perk = perks[ i ]; + if ( perk == "specialty_detectexplosive" ) + { + self.detectexplosives = 1; + } + i++; + } +} + +register_perks() +{ + perks = self.specialty; + self clearperks(); + i = 0; + while ( i < perks.size ) + { + perk = perks[ i ]; + if ( perk != "specialty_null" || issubstr( perk, "specialty_weapon_" ) && perk == "weapon_null" ) + { + i++; + continue; + } + else + { + if ( !level.perksenabled ) + { + i++; + continue; + } + else + { + self setperk( perk ); + } + } + i++; + } +/# + maps/mp/gametypes/_dev::giveextraperks(); +#/ +} + +cac_get_dvar_int( dvar, def ) +{ + return int( cac_get_dvar( dvar, def ) ); +} + +cac_get_dvar( dvar, def ) +{ + if ( getDvar( dvar ) != "" ) + { + return getDvarFloat( dvar ); + } + else + { + setdvar( dvar, def ); + return def; + } +} + +cac_modified_vehicle_damage( victim, attacker, damage, meansofdeath, weapon, inflictor ) +{ + if ( isDefined( victim ) || !isDefined( attacker ) && !isplayer( attacker ) ) + { + return damage; + } + if ( isDefined( damage ) || !isDefined( meansofdeath ) && !isDefined( weapon ) ) + { + return damage; + } + old_damage = damage; + final_damage = damage; + if ( attacker hasperk( "specialty_bulletdamage" ) && isprimarydamage( meansofdeath ) ) + { + final_damage = ( damage * ( 100 + level.cac_bulletdamage_data ) ) / 100; +/# + if ( getDvarInt( #"5ABA6445" ) ) + { + println( "Perk/> " + attacker.name + "'s bullet damage did extra damage to vehicle" ); +#/ + } + } + else + { + if ( attacker hasperk( "specialty_explosivedamage" ) && isplayerexplosiveweapon( weapon, meansofdeath ) ) + { + final_damage = ( damage * ( 100 + level.cac_explosivedamage_data ) ) / 100; +/# + if ( getDvarInt( #"5ABA6445" ) ) + { + println( "Perk/> " + attacker.name + "'s explosive damage did extra damage to vehicle" ); +#/ + } + } + else + { + final_damage = old_damage; + } + } +/# + if ( getDvarInt( #"5ABA6445" ) ) + { + println( "Perk/> Damage Factor: " + ( final_damage / old_damage ) + " - Pre Damage: " + old_damage + " - Post Damage: " + final_damage ); +#/ + } + return int( final_damage ); +} + +cac_modified_damage( victim, attacker, damage, mod, weapon, inflictor, hitloc ) +{ +/# + assert( isDefined( victim ) ); +#/ +/# + assert( isDefined( attacker ) ); +#/ +/# + assert( isplayer( victim ) ); +#/ + if ( victim == attacker ) + { + return damage; + } + if ( !isplayer( attacker ) ) + { + return damage; + } + if ( damage <= 0 ) + { + return damage; + } +/# + debug = 0; + if ( getDvarInt( #"5ABA6445" ) ) + { + debug = 1; +#/ + } + final_damage = damage; + if ( attacker hasperk( "specialty_bulletdamage" ) && isprimarydamage( mod ) ) + { + if ( victim hasperk( "specialty_armorvest" ) && !isheaddamage( hitloc ) ) + { +/# + if ( debug ) + { + println( "Perk/> " + victim.name + "'s armor countered " + attacker.name + "'s increased bullet damage" ); +#/ + } + } + else + { + final_damage = ( damage * ( 100 + level.cac_bulletdamage_data ) ) / 100; +/# + if ( debug ) + { + println( "Perk/> " + attacker.name + "'s bullet damage did extra damage to " + victim.name ); +#/ + } + } + } + else + { + if ( victim hasperk( "specialty_armorvest" ) && isprimarydamage( mod ) && !isheaddamage( hitloc ) ) + { + final_damage = damage * ( level.cac_armorvest_data * 0,01 ); +/# + if ( debug ) + { + println( "Perk/> " + attacker.name + "'s bullet damage did less damage to " + victim.name ); +#/ + } + } + else + { + if ( victim hasperk( "specialty_fireproof" ) && isfiredamage( weapon, mod ) ) + { + final_damage = damage * ( ( 100 - level.cac_fireproof_data ) / 100 ); +/# + if ( debug ) + { + println( "Perk/> " + attacker.name + "'s flames did less damage to " + victim.name ); +#/ + } + } + else + { + if ( attacker hasperk( "specialty_explosivedamage" ) && isplayerexplosiveweapon( weapon, mod ) ) + { + final_damage = ( damage * ( 100 + level.cac_explosivedamage_data ) ) / 100; +/# + if ( debug ) + { + println( "Perk/> " + attacker.name + "'s explosive damage did extra damage to " + victim.name ); +#/ + } + } + else + { + if ( victim hasperk( "specialty_flakjacket" ) && isexplosivedamage( weapon, mod ) && !victim grenadestuck( inflictor ) ) + { + if ( level.hardcoremode ) + { + } + else + { + } + cac_data = level.cac_flakjacket_data; + if ( level.teambased && attacker.team != victim.team ) + { + victim thread maps/mp/_challenges::flakjacketprotected( weapon, attacker ); + } + else + { + if ( attacker != victim ) + { + victim thread maps/mp/_challenges::flakjacketprotected( weapon, attacker ); + } + } + final_damage = int( damage * ( cac_data / 100 ) ); +/# + if ( debug ) + { + println( "Perk/> " + victim.name + "'s flak jacket decreased " + attacker.name + "'s grenade damage" ); +#/ + } + } + } + } + } + } +/# + victim.cac_debug_damage_type = tolower( mod ); + victim.cac_debug_original_damage = damage; + victim.cac_debug_final_damage = final_damage; + victim.cac_debug_location = tolower( hitloc ); + victim.cac_debug_weapon = tolower( weapon ); + victim.cac_debug_range = int( distance( attacker.origin, victim.origin ) ); + if ( debug ) + { + println( "Perk/> Damage Factor: " + ( final_damage / damage ) + " - Pre Damage: " + damage + " - Post Damage: " + final_damage ); +#/ + } + final_damage = int( final_damage ); + if ( final_damage < 1 ) + { + final_damage = 1; + } + return final_damage; +} + +isexplosivedamage( weapon, meansofdeath ) +{ + if ( isDefined( weapon ) ) + { + switch( weapon ) + { + case "briefcase_bomb_mp": + case "concussion_grenade_mp": + case "emp_grenade_mp": + case "flash_grenade_mp": + case "proximity_grenade_mp": + case "tabun_gas_mp": + case "willy_pete_mp": + return 0; + } + } + switch( meansofdeath ) + { + case "MOD_EXPLOSIVE": + case "MOD_GRENADE": + case "MOD_GRENADE_SPLASH": + case "MOD_PROJECTILE_SPLASH": + return 1; + } + return 0; +} + +hastacticalmask( player ) +{ + if ( !player hasperk( "specialty_stunprotection" ) && !player hasperk( "specialty_flashprotection" ) ) + { + return player hasperk( "specialty_proximityprotection" ); + } +} + +isprimarydamage( meansofdeath ) +{ + if ( meansofdeath != "MOD_RIFLE_BULLET" ) + { + return meansofdeath == "MOD_PISTOL_BULLET"; + } +} + +isfiredamage( weapon, meansofdeath ) +{ + if ( !issubstr( weapon, "flame" ) && !issubstr( weapon, "napalmblob_" ) && issubstr( weapon, "napalm_" ) && meansofdeath != "MOD_BURNED" || meansofdeath == "MOD_GRENADE" && meansofdeath == "MOD_GRENADE_SPLASH" ) + { + return 1; + } + if ( getsubstr( weapon, 0, 3 ) == "ft_" ) + { + return 1; + } + return 0; +} + +isplayerexplosiveweapon( weapon, meansofdeath ) +{ + if ( !isexplosivedamage( weapon, meansofdeath ) ) + { + return 0; + } + switch( weapon ) + { + case "airstrike_mp": + case "artillery_mp": + case "cobra_ffar_mp": + case "hind_ffar_mp": + case "mortar_mp": + case "napalm_mp": + return 1; + } + return 1; +} + +isheaddamage( hitloc ) +{ + if ( hitloc != "helmet" && hitloc != "head" ) + { + return hitloc == "neck"; + } +} + +grenadestuck( inflictor ) +{ + if ( isDefined( inflictor ) && isDefined( inflictor.stucktoplayer ) ) + { + return inflictor.stucktoplayer == self; + } +} diff --git a/patch_mp/maps/mp/gametypes/_clientids.gsc b/patch_mp/maps/mp/gametypes/_clientids.gsc new file mode 100644 index 0000000..b17e410 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_clientids.gsc @@ -0,0 +1,16 @@ + +init() +{ + level.clientid = 0; + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player.clientid = level.clientid; + level.clientid++; + } +} diff --git a/patch_mp/maps/mp/gametypes/_copter.gsc b/patch_mp/maps/mp/gametypes/_copter.gsc new file mode 100644 index 0000000..dd916ef --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_copter.gsc @@ -0,0 +1,811 @@ + +init() +{ + level.coptermodel = "vehicle_cobra_helicopter_fly"; + precachemodel( level.coptermodel ); + level.copter_maxaccel = 200; + level.copter_maxvel = 700; + level.copter_rotspeed = 90; + level.copter_accellookahead = 2; + level.coptercenteroffset = vectorScale( ( 0, 0, -1 ), 72 ); + level.coptertargetoffset = vectorScale( ( 0, 0, -1 ), 45 ); + level.copterexplosion = loadfx( "explosions/fx_default_explosion" ); + level.copterfinalexplosion = loadfx( "explosions/fx_large_vehicle_explosion" ); +} + +getabovebuildingslocation( location ) +{ + trace = bullettrace( location + vectorScale( ( 0, 0, -1 ), 10000 ), location, 0, undefined ); + startorigin = trace[ "position" ] + vectorScale( ( 0, 0, -1 ), 514 ); + zpos = 0; + maxxpos = 13; + maxypos = 13; + xpos = 0; + while ( xpos < maxxpos ) + { + ypos = 0; + while ( ypos < maxypos ) + { + thisstartorigin = startorigin + ( ( ( xpos / ( maxxpos - 1 ) ) - 0,5 ) * 1024, ( ( ypos / ( maxypos - 1 ) ) - 0,5 ) * 1024, 0 ); + thisorigin = bullettrace( thisstartorigin, thisstartorigin + vectorScale( ( 0, 0, -1 ), 10000 ), 0, undefined ); + zpos += thisorigin[ "position" ][ 2 ]; + ypos++; + } + xpos++; + } + zpos /= maxxpos * maxypos; + zpos += 850; + return ( location[ 0 ], location[ 1 ], zpos ); +} + +vectorangle( v1, v2 ) +{ + dot = vectordot( v1, v2 ); + if ( dot >= 1 ) + { + return 0; + } + else + { + if ( dot <= -1 ) + { + return 180; + } + } + return acos( dot ); +} + +vectortowardsothervector( v1, v2, angle ) +{ + dot = vectordot( v1, v2 ); + if ( dot <= -1 ) + { + return v1; + } + v3 = vectornormalize( v2 - vectorScale( v1, dot ) ); + return vectorScale( v1, cos( angle ) ) + vectorScale( v3, sin( angle ) ); +} + +veclength( v ) +{ + return distance( ( 0, 0, -1 ), v ); +} + +createcopter( location, team, damagetrig ) +{ + location = getabovebuildingslocation( location ); + scriptorigin = spawn( "script_origin", location ); + scriptorigin.angles = vectorToAngle( ( 0, 0, -1 ) ); + copter = spawn( "script_model", location ); + copter.angles = vectorToAngle( ( 0, 0, -1 ) ); + copter linkto( scriptorigin ); + scriptorigin.copter = copter; + copter setmodel( level.coptermodel ); + copter playloopsound( "mp_copter_ambience" ); + damagetrig.origin = scriptorigin.origin; + damagetrig thread mylinkto( scriptorigin ); + scriptorigin.damagetrig = damagetrig; + scriptorigin.finaldest = location; + scriptorigin.finalzdest = location[ 2 ]; + scriptorigin.desireddir = ( 0, 0, -1 ); + scriptorigin.desireddirentity = undefined; + scriptorigin.desireddirentityoffset = ( 0, 0, -1 ); + scriptorigin.vel = ( 0, 0, -1 ); + scriptorigin.dontascend = 0; + scriptorigin.health = 2000; + if ( getDvar( #"A8262D2E" ) != "" ) + { + scriptorigin.health = getDvarFloat( #"A8262D2E" ); + } + scriptorigin.team = team; + scriptorigin thread copterai(); + scriptorigin thread copterdamage( damagetrig ); + return scriptorigin; +} + +makecopterpassive() +{ + self.damagetrig notify( "unlink" ); + self.damagetrig = undefined; + self notify( "passive" ); + self.desireddirentity = undefined; + self.desireddir = undefined; +} + +makecopteractive( damagetrig ) +{ + damagetrig.origin = self.origin; + damagetrig thread mylinkto( self ); + self.damagetrig = damagetrig; + self thread copterai(); + self thread copterdamage( damagetrig ); +} + +mylinkto( obj ) +{ + self endon( "unlink" ); + while ( 1 ) + { + self.angles = obj.angles; + self.origin = obj.origin; + wait 0,1; + } +} + +setcopterdefensearea( areaent ) +{ + self.areaent = areaent; + self.areadescentpoints = []; + if ( isDefined( areaent.target ) ) + { + self.areadescentpoints = getentarray( areaent.target, "targetname" ); + } + i = 0; + while ( i < self.areadescentpoints.size ) + { + self.areadescentpoints[ i ].targetent = getent( self.areadescentpoints[ i ].target, "targetname" ); + i++; + } +} + +copterai() +{ + self thread coptermove(); + self thread coptershoot(); + self endon( "death" ); + self endon( "passive" ); + flying = 1; + descendingent = undefined; + reacheddescendingent = 0; + returningtoarea = 0; + while ( 1 ) + { + while ( !isDefined( self.areaent ) ) + { + wait 1; + } + players = level.players; + enemytargets = []; + while ( self.team != "neutral" ) + { + i = 0; + while ( i < players.size ) + { + if ( isalive( players[ i ] ) && isDefined( players[ i ].pers[ "team" ] ) && players[ i ].pers[ "team" ] != self.team && !isDefined( players[ i ].usingobj ) ) + { + playerorigin = players[ i ].origin; + playerorigin = ( playerorigin[ 0 ], playerorigin[ 1 ], self.areaent.origin[ 2 ] ); + if ( distance( playerorigin, self.areaent.origin ) < self.areaent.radius ) + { + enemytargets[ enemytargets.size ] = players[ i ]; + } + } + i++; + } + } + insidetargets = []; + outsidetargets = []; + skyheight = bullettrace( self.origin, self.origin + vectorScale( ( 0, 0, -1 ), 10000 ), 0, undefined )[ "position" ][ 2 ] - 10; + besttarget = undefined; + bestweight = 0; + i = 0; + while ( i < enemytargets.size ) + { + inside = 0; + trace = bullettrace( enemytargets[ i ].origin + vectorScale( ( 0, 0, -1 ), 10 ), enemytargets[ i ].origin + vectorScale( ( 0, 0, -1 ), 10000 ), 0, undefined ); + if ( trace[ "position" ][ 2 ] >= skyheight ) + { + outsidetargets[ outsidetargets.size ] = enemytargets[ i ]; + i++; + continue; + } + else + { + insidetargets[ insidetargets.size ] = enemytargets[ i ]; + } + i++; + } + gotopos = undefined; + calcedgotopos = 0; + olddescendingent = undefined; + if ( flying ) + { + if ( outsidetargets.size == 0 && insidetargets.size > 0 && self.areadescentpoints.size > 0 ) + { + flying = 0; + result = determinebestent( insidetargets, self.areadescentpoints, self.origin ); + descendingent = result[ "descendEnt" ]; + if ( isDefined( descendingent ) ) + { + gotopos = result[ "position" ]; + break; + } + else + { + flying = 1; + } + } + } + else olddescendingent = descendingent; + if ( insidetargets.size == 0 ) + { + flying = 1; + } + else + { + if ( outsidetargets.size > 0 ) + { + if ( !isDefined( descendingent ) ) + { + flying = 1; + break; + } + else + { + calcedgotopos = 1; + gotopos = determinebestpos( insidetargets, descendingent, self.origin ); + if ( !isDefined( gotopos ) ) + { + flying = 1; + } + } + } + if ( isDefined( descendingent ) ) + { + if ( !calcedgotopos ) + { + gotopos = determinebestpos( insidetargets, descendingent, self.origin ); + } + } + if ( !isDefined( gotopos ) ) + { + result = determinebestent( insidetargets, self.areadescentpoints, self.origin ); + if ( isDefined( result[ "descendEnt" ] ) ) + { + descendingent = result[ "descendEnt" ]; + gotopos = result[ "position" ]; + reacheddescendingent = 0; + break; + } + else if ( isDefined( descendingent ) ) + { + if ( isDefined( self.finaldest ) ) + { + gotopos = self.finaldest; + } + else + { + gotopos = descendingent.origin; + } + break; + } + else + { + gotopos = undefined; + } + } + if ( !isDefined( gotopos ) ) + { + flying = 1; + } + } + if ( flying ) + { + desireddist = 2560; + disttoarea = distance( ( self.origin[ 0 ], self.origin[ 1 ], self.areaent.origin[ 2 ] ), self.areaent.origin ); + if ( outsidetargets.size == 0 && disttoarea > ( self.areaent.radius + ( desireddist * 0,25 ) ) ) + { + returningtoarea = 1; + } + else + { + if ( disttoarea < ( self.areaent.radius * 0,5 ) ) + { + returningtoarea = 0; + } + } + while ( outsidetargets.size == 0 && !returningtoarea ) + { + while ( self.team != "neutral" ) + { + i = 0; + while ( i < players.size ) + { + if ( isalive( players[ i ] ) && isDefined( players[ i ].pers[ "team" ] ) && players[ i ].pers[ "team" ] != self.team && !isDefined( players[ i ].usingobj ) ) + { + playerorigin = players[ i ].origin; + playerorigin = ( playerorigin[ 0 ], playerorigin[ 1 ], self.areaent.origin[ 2 ] ); + if ( distance( players[ i ].origin, self.areaent.origin ) > self.areaent.radius ) + { + outsidetargets[ outsidetargets.size ] = players[ i ]; + } + } + i++; + } + } + } + best = undefined; + bestdist = 0; + i = 0; + while ( i < outsidetargets.size ) + { + dist = abs( distance( outsidetargets[ i ].origin, self.origin ) - desireddist ); + if ( !isDefined( best ) || dist < bestdist ) + { + best = outsidetargets[ i ]; + bestdist = dist; + } + i++; + } + if ( isDefined( best ) ) + { + attackpos = best.origin + level.coptertargetoffset; + gotopos = determinebestattackpos( attackpos, self.origin, desireddist ); + self setcopterdest( gotopos, 0 ); + self.desireddir = vectornormalize( attackpos - gotopos ); + self.desireddirentity = best; + self.desireddirentityoffset = level.coptertargetoffset; + wait 1; + } + else + { + gotopos = getrandompos( self.areaent.origin, self.areaent.radius ); + self setcopterdest( gotopos, 0 ); + self.desireddir = undefined; + self.desireddirentity = undefined; + wait 1; + } + continue; + } + else if ( distance( self.origin, descendingent.origin ) < descendingent.radius ) + { + reacheddescendingent = 1; + } + if ( isDefined( olddescendingent ) ) + { + godirectly = olddescendingent == descendingent; + } + if ( godirectly ) + { + godirectly = reacheddescendingent; + } + self.desireddir = vectornormalize( descendingent.targetent.origin - gotopos - level.coptercenteroffset ); + self.desireddirentity = descendingent.targetent; + self.desireddirentityoffset = ( 0, 0, -1 ); + if ( gotopos != self.origin ) + { + self setcopterdest( gotopos - level.coptercenteroffset, 1, godirectly ); + wait 0,3; + continue; + } + else + { + wait 0,3; + } + } +} + +determinebestpos( targets, descendent, startorigin ) +{ + targetpos = descendent.targetent.origin; + circleradius = distance( targetpos, descendent.origin ); + bestpoint = undefined; + bestdist = 0; + i = 0; + while ( i < targets.size ) + { + enemypos = targets[ i ].origin + level.coptertargetoffset; + passed = bullettracepassed( enemypos, targetpos, 0, undefined ); + if ( passed ) + { + dir = targetpos - enemypos; + dir = ( dir[ 0 ], dir[ 1 ], 0 ); + isect = vectorScale( vectornormalize( dir ), circleradius ) + targetpos; + isect = ( isect[ 0 ], isect[ 1 ], descendent.origin[ 2 ] ); + dist = distance( isect, descendent.origin ); + if ( dist <= descendent.radius ) + { + dist = distance( isect, startorigin ); + if ( !isDefined( bestpoint ) || dist < bestdist ) + { + bestdist = dist; + bestpoint = isect; + } + } + } + i++; + } + return bestpoint; +} + +determinebestent( targets, descendents, startorigin ) +{ + result = []; + bestpos = undefined; + bestent = 0; + bestdist = 0; + i = 0; + while ( i < descendents.size ) + { + thispos = determinebestpos( targets, descendents[ i ], startorigin ); + if ( isDefined( thispos ) ) + { + thisdist = distance( thispos, startorigin ); + if ( !isDefined( bestpos ) || thisdist < bestdist ) + { + bestpos = thispos; + bestent = i; + bestdist = thisdist; + } + } + i++; + } + if ( isDefined( bestpos ) ) + { + result[ "descendEnt" ] = descendents[ bestent ]; + result[ "position" ] = bestpos; + return result; + } + return result; +} + +determinebestattackpos( targetpos, curpos, desireddist ) +{ + targetposcopterheight = ( targetpos[ 0 ], targetpos[ 1 ], curpos[ 2 ] ); + attackdirx = curpos - targetposcopterheight; + attackdirx = vectornormalize( attackdirx ); + attackdiry = ( 0 - attackdirx[ 1 ], attackdirx[ 0 ], 0 ); + bestpos = undefined; + bestdist = 0; + i = 0; + while ( i < 8 ) + { + theta = ( i / 8 ) * 360; + thisdir = vectorScale( attackdirx, cos( theta ) ) + vectorScale( attackdiry, sin( theta ) ); + traceend = targetposcopterheight + vectorScale( thisdir, desireddist ); + losexists = bullettracepassed( targetpos, traceend, 0, undefined ); + if ( losexists ) + { + thisdist = distance( traceend, curpos ); + if ( !isDefined( bestpos ) || thisdist < bestdist ) + { + bestpos = traceend; + bestdist = thisdist; + } + } + i++; + } + gotopos = undefined; + if ( isDefined( bestpos ) ) + { + gotopos = bestpos; + } + else dist = distance( targetposcopterheight, curpos ); + if ( dist > desireddist ) + { + gotopos = self.origin + vectorScale( vectornormalize( attackdirx ), 0 - dist - desireddist ); + } + else + { + gotopos = self.origin; + } + return gotopos; +} + +getrandompos( origin, radius ) +{ + pos = origin + ( ( randomfloat( 2 ) - 1 ) * radius, ( randomfloat( 2 ) - 1 ) * radius, 0 ); + while ( distancesquared( pos, origin ) > ( radius * radius ) ) + { + pos = origin + ( ( randomfloat( 2 ) - 1 ) * radius, ( randomfloat( 2 ) - 1 ) * radius, 0 ); + } + return pos; +} + +coptershoot() +{ + self endon( "death" ); + self endon( "passive" ); + costhreshold = cos( 10 ); + while ( 1 ) + { + if ( isDefined( self.desireddirentity ) && isDefined( self.desireddirentity.origin ) ) + { + mypos = self.origin + level.coptercenteroffset; + enemypos = self.desireddirentity.origin + self.desireddirentityoffset; + curdir = anglesToForward( self.angles ); + enemydirraw = enemypos - mypos; + enemydir = vectornormalize( enemydirraw ); + if ( vectordot( curdir, enemydir ) > costhreshold ) + { + canseetarget = bullettracepassed( mypos, enemypos, 0, undefined ); + if ( !canseetarget && isplayer( self.desireddirentity ) && isalive( self.desireddirentity ) ) + { + canseetarget = bullettracepassed( mypos, self.desireddirentity geteye(), 0, undefined ); + } + if ( canseetarget ) + { + self playsound( "mp_copter_shoot" ); + numshots = 20; + i = 0; + while ( i < numshots ) + { + mypos = self.origin + level.coptercenteroffset; + dir = anglesToForward( self.angles ); + dir += ( ( randomfloat( 2 ) - 1 ) * 0,015, ( randomfloat( 2 ) - 1 ) * 0,015, ( randomfloat( 2 ) - 1 ) * 0,015 ); + dir = vectornormalize( dir ); + self mymagicbullet( mypos, dir ); + wait 0,075; + i++; + } + wait 0,25; + } + } + } + wait 0,25; + } +} + +mymagicbullet( pos, dir ) +{ + damage = 20; + if ( getDvar( #"9E8F8CB7" ) != "" ) + { + damage = getDvarInt( #"9E8F8CB7" ); + } + trace = bullettrace( pos, pos + vectorScale( dir, 10000 ), 1, undefined ); + if ( isDefined( trace[ "entity" ] ) && isplayer( trace[ "entity" ] ) && isalive( trace[ "entity" ] ) ) + { + trace[ "entity" ] thread [[ level.callbackplayerdamage ]]( self, self, damage, 0, "MOD_RIFLE_BULLET", "copter", self.origin, dir, "none", 0, 0 ); + } +} + +setcopterdest( newlocation, descend, dontascend ) +{ + self.finaldest = getabovebuildingslocation( newlocation ); + if ( isDefined( descend ) && descend ) + { + self.finalzdest = newlocation[ 2 ]; + } + else + { + self.finalzdest = self.finaldest[ 2 ]; + } + self.intransit = 1; + self.dontascend = 0; + if ( isDefined( dontascend ) ) + { + self.dontascend = dontascend; + } +} + +notifyarrived() +{ + wait 0,05; + self notify( "arrived" ); +} + +coptermove() +{ + self endon( "death" ); + if ( isDefined( self.coptermoverunning ) ) + { + return; + } + self.coptermoverunning = 1; + self.intransit = 0; + interval = 0,15; + zinterp = 0,1; + tiltamnt = 0; + while ( 1 ) + { + horizdistsquared = distancesquared( ( self.origin[ 0 ], self.origin[ 1 ], 0 ), ( self.finaldest[ 0 ], self.finaldest[ 1 ], 0 ) ); + donemoving = horizdistsquared < 100; + neardest = horizdistsquared < 65536; + self.intransit = 1; + desiredz = 0; + movinghorizontally = 1; + movingvertically = 0; + if ( self.dontascend ) + { + movingvertically = 1; + } + else if ( !neardest ) + { + desiredz = getabovebuildingslocation( self.origin )[ 2 ]; + movinghorizontally = abs( self.origin[ 2 ] - desiredz ) <= 256; + movingvertically = !movinghorizontally; + } + else + { + movingvertically = 1; + } + if ( movinghorizontally ) + { + if ( movingvertically ) + { + thisdest = ( self.finaldest[ 0 ], self.finaldest[ 1 ], self.finalzdest ); + } + else + { + thisdest = self.finaldest; + } + } + else + { +/# + assert( movingvertically ); +#/ + thisdest = ( self.origin[ 0 ], self.origin[ 1 ], desiredz ); + } + movevec = thisdest - self.origin; + idealaccel = vectorScale( thisdest - ( self.origin + vectorScale( self.vel, level.copter_accellookahead ) ), interval ); + vlen = veclength( idealaccel ); + if ( vlen > level.copter_maxaccel ) + { + idealaccel = vectorScale( idealaccel, level.copter_maxaccel / vlen ); + } + self.vel += idealaccel; + vlen = veclength( self.vel ); + if ( vlen > level.copter_maxvel ) + { + self.vel = vectorScale( self.vel, level.copter_maxvel / vlen ); + } + thisdest = self.origin + vectorScale( self.vel, interval ); + self moveto( thisdest, interval * 0,999 ); + speed = veclength( self.vel ); + if ( isDefined( self.desireddirentity ) && isDefined( self.desireddirentity.origin ) ) + { + self.destdir = vectornormalize( ( self.desireddirentity.origin + self.desireddirentityoffset ) - ( self.origin + level.coptercenteroffset ) ); + } + else + { + if ( isDefined( self.desireddir ) ) + { + self.destdir = self.desireddir; + break; + } + else if ( movingvertically ) + { + self.destdir = anglesToForward( self.angles ); + self.destdir = vectornormalize( ( self.destdir[ 0 ], self.destdir[ 1 ], 0 ) ); + break; + } + else + { + tiltamnt = speed / level.copter_maxvel; + tiltamnt = ( tiltamnt - 0,1 ) / 0,9; + if ( tiltamnt < 0 ) + { + tiltamnt = 0; + } + self.destdir = movevec; + self.destdir = vectornormalize( ( self.destdir[ 0 ], self.destdir[ 1 ], 0 ) ); + tiltamnt *= 1 - ( vectorangle( anglesToForward( self.angles ), self.destdir ) / 180 ); + self.destdir = vectornormalize( ( self.destdir[ 0 ], self.destdir[ 1 ], tiltamnt * -0,4 ) ); + } + } + newdir = self.destdir; + if ( newdir[ 2 ] < -0,4 ) + { + newdir = vectornormalize( ( newdir[ 0 ], newdir[ 1 ], -0,4 ) ); + } + copterangles = self.angles; + copterangles = combineangles( copterangles, vectorScale( ( 0, 0, -1 ), 90 ) ); + olddir = anglesToForward( copterangles ); + thisrotspeed = level.copter_rotspeed; + olddir2d = vectornormalize( ( olddir[ 0 ], olddir[ 1 ], 0 ) ); + newdir2d = vectornormalize( ( newdir[ 0 ], newdir[ 1 ], 0 ) ); + angle = vectorangle( olddir2d, newdir2d ); + angle3d = vectorangle( olddir, newdir ); + if ( angle > 0,001 && thisrotspeed > 0,001 ) + { + thisangle = thisrotspeed * interval; + if ( thisangle > angle ) + { + thisangle = angle; + } + newdir2d = vectortowardsothervector( olddir2d, newdir2d, thisangle ); + oldz = olddir[ 2 ] / veclength( ( olddir[ 0 ], olddir[ 1 ], 0 ) ); + newz = newdir[ 2 ] / veclength( ( newdir[ 0 ], newdir[ 1 ], 0 ) ); + interpz = oldz + ( ( newz - oldz ) * ( thisangle / angle ) ); + newdir = vectornormalize( ( newdir2d[ 0 ], newdir2d[ 1 ], interpz ) ); + copterangles = vectorToAngle( newdir ); + copterangles = combineangles( copterangles, vectorScale( ( 0, 0, -1 ), 90 ) ); + self rotateto( copterangles, interval * 0,999 ); + } + else + { + if ( angle3d > 0,001 && thisrotspeed > 0,001 ) + { + thisangle = thisrotspeed * interval; + if ( thisangle > angle3d ) + { + thisangle = angle3d; + } + newdir = vectortowardsothervector( olddir, newdir, thisangle ); + newdir = vectornormalize( newdir ); + copterangles = vectorToAngle( newdir ); + copterangles = combineangles( copterangles, vectorScale( ( 0, 0, -1 ), 90 ) ); + self rotateto( copterangles, interval * 0,999 ); + } + } + wait interval; + } +} + +copterdamage( damagetrig ) +{ + self endon( "passive" ); + while ( 1 ) + { + damagetrig waittill( "damage", amount, attacker ); + while ( isDefined( attacker ) && isplayer( attacker ) && isDefined( attacker.pers[ "team" ] ) && attacker.pers[ "team" ] == self.team ) + { + continue; + } + self.health -= amount; + if ( self.health <= 0 ) + { + self thread copterdie(); + return; + } + } +} + +copterdie() +{ + self endon( "passive" ); + self death_notify_wrapper(); + self.dead = 1; + self thread copterexplodefx(); + interval = 0,2; + rottime = 15; + self rotateyaw( 360 + randomfloat( 360 ), rottime ); + self rotatepitch( 360 + randomfloat( 360 ), rottime ); + self rotateroll( 360 + randomfloat( 360 ), rottime ); + while ( 1 ) + { + self.vel += vectorScale( vectorScale( ( 0, 0, -1 ), 200 ), interval ); + newpos = self.origin + vectorScale( self.vel, interval ); + pathclear = bullettracepassed( self.origin, newpos, 0, undefined ); + if ( !pathclear ) + { + break; + } + else + { + self moveto( newpos, interval * 0,999 ); + wait interval; + } + } + playfx( level.copterfinalexplosion, self.origin ); + fakeself = spawn( "script_origin", self.origin ); + fakeself playsound( "mp_copter_explosion" ); + self notify( "finaldeath" ); + deletecopter(); + wait 2; + fakeself delete(); +} + +deletecopter() +{ + if ( isDefined( self.damagetrig ) ) + { + self.damagetrig notify( "unlink" ); + self.damagetrig = undefined; + } + self.copter delete(); + self delete(); +} + +copterexplodefx() +{ + self endon( "finaldeath" ); + while ( 1 ) + { + playfx( level.copterexplosion, self.origin ); + self playsound( "mp_copter_explosion" ); + wait ( 0,5 + randomfloat( 1 ) ); + } +} diff --git a/patch_mp/maps/mp/gametypes/_damagefeedback.gsc b/patch_mp/maps/mp/gametypes/_damagefeedback.gsc new file mode 100644 index 0000000..5bf5a09 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_deathicons.gsc b/patch_mp/maps/mp/gametypes/_deathicons.gsc new file mode 100644 index 0000000..79abf2e --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_deathicons.gsc @@ -0,0 +1,98 @@ +#include maps/mp/gametypes/_deathicons; +#include maps/mp/gametypes/_globallogic_utils; + +init() +{ + if ( !isDefined( level.ragdoll_override ) ) + { + level.ragdoll_override = ::ragdoll_override; + } + if ( !level.teambased ) + { + return; + } + precacheshader( "headicon_dead" ); + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player.selfdeathicons = []; + } +} + +updatedeathiconsenabled() +{ +} + +adddeathicon( entity, dyingplayer, team, timeout ) +{ + if ( !level.teambased ) + { + return; + } + iconorg = entity.origin; + dyingplayer endon( "spawned_player" ); + dyingplayer endon( "disconnect" ); + wait 0,05; + maps/mp/gametypes/_globallogic_utils::waittillslowprocessallowed(); +/# + assert( isDefined( level.teams[ team ] ) ); +#/ + if ( getDvar( "ui_hud_showdeathicons" ) == "0" ) + { + return; + } + if ( level.hardcoremode ) + { + return; + } + if ( isDefined( self.lastdeathicon ) ) + { + self.lastdeathicon destroy(); + } + newdeathicon = newteamhudelem( team ); + newdeathicon.x = iconorg[ 0 ]; + newdeathicon.y = iconorg[ 1 ]; + newdeathicon.z = iconorg[ 2 ] + 54; + newdeathicon.alpha = 0,61; + newdeathicon.archived = 1; + if ( level.splitscreen ) + { + newdeathicon setshader( "headicon_dead", 14, 14 ); + } + else + { + newdeathicon setshader( "headicon_dead", 7, 7 ); + } + newdeathicon setwaypoint( 1 ); + self.lastdeathicon = newdeathicon; + newdeathicon thread destroyslowly( timeout ); +} + +destroyslowly( timeout ) +{ + self endon( "death" ); + wait timeout; + self fadeovertime( 1 ); + self.alpha = 0; + wait 1; + self destroy(); +} + +ragdoll_override( idamage, smeansofdeath, sweapon, shitloc, vdir, vattackerorigin, deathanimduration, einflictor, ragdoll_jib, body ) +{ + if ( smeansofdeath == "MOD_FALLING" && self isonground() == 1 ) + { + body startragdoll(); + if ( !isDefined( self.switching_teams ) ) + { + thread maps/mp/gametypes/_deathicons::adddeathicon( body, self, self.team, 5 ); + } + return 1; + } + return 0; +} diff --git a/patch_mp/maps/mp/gametypes/_dev.gsc b/patch_mp/maps/mp/gametypes/_dev.gsc new file mode 100644 index 0000000..86a3a5e --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_dev_class.gsc b/patch_mp/maps/mp/gametypes/_dev_class.gsc new file mode 100644 index 0000000..688d59c --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_dev_class.gsc @@ -0,0 +1,580 @@ +#include maps/mp/gametypes/_dev; +#include maps/mp/_utility; + +dev_cac_init() +{ +/# + dev_cac_overlay = 0; + dev_cac_camera_on = 0; + level thread dev_cac_gdt_update_think(); + for ( ;; ) + { + wait 0,5; + reset = 1; + if ( getDvar( #"E6D8B517" ) != "" ) + { + continue; + } + else + { + host = gethostplayer(); + if ( !isDefined( level.dev_cac_player ) ) + { + level.dev_cac_player = host; + } + switch( getDvar( "devgui_dev_cac" ) ) + { + case "": + reset = 0; + break; + case "dpad_body": + host thread dev_cac_dpad_think( "body", ::dev_cac_cycle_body, "" ); + break; + case "dpad_head": + host thread dev_cac_dpad_think( "head", ::dev_cac_cycle_head, "" ); + break; + case "dpad_character": + host thread dev_cac_dpad_think( "character", ::dev_cac_cycle_character, "" ); + break; + case "next_player": + dev_cac_cycle_player( 1 ); + break; + case "prev_player": + dev_cac_cycle_player( 0 ); + break; + case "cac_overlay": + level notify( "dev_cac_overlay_think" ); + if ( !dev_cac_overlay ) + { + level thread dev_cac_overlay_think(); + } + dev_cac_overlay = !dev_cac_overlay; + break; + case "best_bullet_armor": + dev_cac_set_model_range( ::sort_greatest, "armor_bullet" ); + break; + case "worst_bullet_armor": + dev_cac_set_model_range( ::sort_least, "armor_bullet" ); + break; + case "best_explosive_armor": + dev_cac_set_model_range( ::sort_greatest, "armor_explosive" ); + break; + case "worst_explosive_armor": + dev_cac_set_model_range( ::sort_least, "armor_explosive" ); + break; + case "best_mobility": + dev_cac_set_model_range( ::sort_greatest, "mobility" ); + break; + case "worst_mobility": + dev_cac_set_model_range( ::sort_least, "mobility" ); + break; + case "camera": + dev_cac_camera_on = !dev_cac_camera_on; + dev_cac_camera( dev_cac_camera_on ); + break; + case "dpad_camo": + host thread dev_cac_dpad_think( "camo", ::dev_cac_cycle_render_options, "camo" ); + break; + case "dpad_meleecamo": + host thread dev_cac_dpad_think( "meleecamo", ::dev_cac_cycle_render_options, "meleecamo" ); + break; + case "dpad_lens": + host thread dev_cac_dpad_think( "lens", ::dev_cac_cycle_render_options, "lens" ); + break; + case "dpad_reticle": + host thread dev_cac_dpad_think( "reticle", ::dev_cac_cycle_render_options, "reticle" ); + break; + case "dpad_reticle_color": + host thread dev_cac_dpad_think( "reticle color", ::dev_cac_cycle_render_options, "reticle_color" ); + break; + case "dpad_emblem": + host thread dev_cac_dpad_think( "emblem", ::dev_cac_cycle_render_options, "emblem" ); + break; + case "dpad_tag": + host thread dev_cac_dpad_think( "tag", ::dev_cac_cycle_render_options, "tag" ); + break; + case "dpad_facepaint_pattern": + host thread dev_cac_dpad_think( "facepaint pattern", ::dev_cac_cycle_render_options, "facepaint_pattern" ); + break; + case "dpad_facepaint_color": + host thread dev_cac_dpad_think( "facepaint color", ::dev_cac_cycle_render_options, "facepaint_color" ); + break; + case "dpad_reset": + host notify( "dev_cac_dpad_think" ); + break; + } + if ( reset ) + { + setdvar( "devgui_dev_cac", "" ); + } + } +#/ + } +} + +dev_cac_camera( on ) +{ +/# + if ( on ) + { + self setclientthirdperson( 1 ); + setdvar( "cg_thirdPersonAngle", "185" ); + setdvar( "cg_thirdPersonRange", "138" ); + setdvar( "cg_fov", "20" ); + } + else + { + self setclientthirdperson( 0 ); + setdvar( "cg_fov", getDvar( "cg_fov_default" ) ); +#/ + } +} + +dev_cac_dpad_think( part_name, cycle_function, tag ) +{ +/# + self notify( "dev_cac_dpad_think" ); + self endon( "dev_cac_dpad_think" ); + self endon( "disconnect" ); + iprintln( "Previous " + part_name + " bound to D-Pad Left" ); + iprintln( "Next " + part_name + " bound to D-Pad Right" ); + dpad_left = 0; + dpad_right = 0; + level.dev_cac_player thread highlight_player(); + for ( ;; ) + { + self setactionslot( 3, "" ); + self setactionslot( 4, "" ); + if ( !dpad_left && self buttonpressed( "DPAD_LEFT" ) ) + { + [[ cycle_function ]]( 0, tag ); + dpad_left = 1; + } + else + { + if ( !self buttonpressed( "DPAD_LEFT" ) ) + { + dpad_left = 0; + } + } + if ( !dpad_right && self buttonpressed( "DPAD_RIGHT" ) ) + { + [[ cycle_function ]]( 1, tag ); + dpad_right = 1; + } + else + { + if ( !self buttonpressed( "DPAD_RIGHT" ) ) + { + dpad_right = 0; + } + } + wait 0,05; +#/ + } +} + +next_in_list( value, list ) +{ +/# + if ( !isDefined( value ) ) + { + return list[ 0 ]; + } + i = 0; + while ( i < list.size ) + { + if ( value == list[ i ] ) + { + if ( isDefined( list[ i + 1 ] ) ) + { + value = list[ i + 1 ]; + } + else + { + value = list[ 0 ]; + } + break; + } + else + { + i++; + } + } + return value; +#/ +} + +prev_in_list( value, list ) +{ +/# + if ( !isDefined( value ) ) + { + return list[ 0 ]; + } + i = 0; + while ( i < list.size ) + { + if ( value == list[ i ] ) + { + if ( isDefined( list[ i - 1 ] ) ) + { + value = list[ i - 1 ]; + } + else + { + value = list[ list.size - 1 ]; + } + break; + } + else + { + i++; + } + } + return value; +#/ +} + +dev_cac_set_player_model() +{ +/# + self.tag_stowed_back = undefined; + self.tag_stowed_hip = undefined; +#/ +} + +dev_cac_cycle_body( forward, tag ) +{ +/# + if ( !dev_cac_player_valid() ) + { + return; + } + player = level.dev_cac_player; + keys = getarraykeys( level.cac_functions[ "set_body_model" ] ); + if ( forward ) + { + player.cac_body_type = next_in_list( player.cac_body_type, keys ); + } + else + { + player.cac_body_type = prev_in_list( player.cac_body_type, keys ); + } + player dev_cac_set_player_model(); +#/ +} + +dev_cac_cycle_head( forward, tag ) +{ +/# + if ( !dev_cac_player_valid() ) + { + return; + } + player = level.dev_cac_player; + keys = getarraykeys( level.cac_functions[ "set_head_model" ] ); + if ( forward ) + { + player.cac_head_type = next_in_list( player.cac_head_type, keys ); + } + else + { + player.cac_head_type = prev_in_list( player.cac_head_type, keys ); + } + player.cac_hat_type = "none"; + player dev_cac_set_player_model(); +#/ +} + +dev_cac_cycle_character( forward, tag ) +{ +/# + if ( !dev_cac_player_valid() ) + { + return; + } + player = level.dev_cac_player; + keys = getarraykeys( level.cac_functions[ "set_body_model" ] ); + if ( forward ) + { + player.cac_body_type = next_in_list( player.cac_body_type, keys ); + } + else + { + player.cac_body_type = prev_in_list( player.cac_body_type, keys ); + } + player.cac_hat_type = "none"; + player dev_cac_set_player_model(); +#/ +} + +dev_cac_cycle_render_options( forward, tag ) +{ +/# + if ( !dev_cac_player_valid() ) + { + return; + } + level.dev_cac_player nextplayerrenderoption( tag, forward ); +#/ +} + +dev_cac_player_valid() +{ +/# + if ( isDefined( level.dev_cac_player ) ) + { + return level.dev_cac_player.sessionstate == "playing"; +#/ + } +} + +dev_cac_cycle_player( forward ) +{ +/# + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( forward ) + { + level.dev_cac_player = next_in_list( level.dev_cac_player, players ); + } + else + { + level.dev_cac_player = prev_in_list( level.dev_cac_player, players ); + } + if ( dev_cac_player_valid() ) + { + level.dev_cac_player thread highlight_player(); + return; + } + i++; + } + level.dev_cac_player = undefined; +#/ +} + +highlight_player() +{ +/# + self sethighlighted( 1 ); + wait 1; + self sethighlighted( 0 ); +#/ +} + +dev_cac_overlay_think() +{ +/# + hud = dev_cac_overlay_create(); + level thread dev_cac_overlay_update( hud ); + level waittill( "dev_cac_overlay_think" ); + dev_cac_overlay_destroy( hud ); +#/ +} + +dev_cac_overlay_update( hud ) +{ +/# +#/ +} + +dev_cac_overlay_destroy( hud ) +{ +/# + i = 0; + while ( i < hud.menu.size ) + { + hud.menu[ i ] destroy(); + i++; + } + hud destroy(); + setdvar( "player_debugSprint", "0" ); +#/ +} + +dev_cac_overlay_create() +{ +/# + x = -80; + y = 140; + menu_name = "dev_cac_debug"; + hud = maps/mp/gametypes/_dev::new_hud( menu_name, undefined, x, y, 1 ); + hud setshader( "white", 185, 285 ); + hud.alignx = "left"; + hud.aligny = "top"; + hud.sort = 10; + hud.alpha = 0,6; + hud.color = vectorScale( ( 0, 0, 0 ), 0,5 ); + x_offset = 100; + hud.menu[ 0 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "NAME", x + 5, y + 10, 1,3 ); + hud.menu[ 1 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "MODELS", x + 5, y + 25, 1 ); + hud.menu[ 2 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Body:", x + 5, y + 35, 1 ); + hud.menu[ 3 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Head:", x + 5, y + 45, 1 ); + hud.menu[ 4 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Head Gear:", x + 5, y + 55, 1 ); + hud.menu[ 5 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "MOBILITY", x + 5, y + 70, 1 ); + hud.menu[ 6 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Body:", x + 5, y + 80, 1 ); + hud.menu[ 7 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Head Gear:", x + 5, y + 90, 1 ); + hud.menu[ 8 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Speed Scale:", x + 5, y + 100, 1 ); + hud.menu[ 9 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Sprint Duration:", x + 5, y + 110, 1 ); + hud.menu[ 10 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Sprint Cooldown:", x + 5, y + 120, 1 ); + hud.menu[ 11 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "ARMOR - BULLET", x + 5, y + 135, 1 ); + hud.menu[ 12 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Body:", x + 5, y + 145, 1 ); + hud.menu[ 13 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Head Gear:", x + 5, y + 155, 1 ); + hud.menu[ 14 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "ARMOR - EXPLOSIVE", x + 5, y + 170, 1 ); + hud.menu[ 15 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Body:", x + 5, y + 180, 1 ); + hud.menu[ 16 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Head Gear:", x + 5, y + 190, 1 ); + hud.menu[ 17 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "DAMAGE", x + 5, y + 205, 1 ); + hud.menu[ 18 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Type:", x + 5, y + 215, 1 ); + hud.menu[ 19 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Original:", x + 5, y + 225, 1 ); + hud.menu[ 20 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Final:", x + 5, y + 235, 1 ); + hud.menu[ 21 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Gain/Loss:", x + 5, y + 245, 1 ); + hud.menu[ 22 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Location:", x + 5, y + 255, 1 ); + hud.menu[ 23 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Weapon:", x + 5, y + 265, 1 ); + hud.menu[ 24 ] = maps/mp/gametypes/_dev::new_hud( menu_name, " Range:", x + 5, y + 275, 1 ); + x_offset = 65; + hud.menu[ 25 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 35, 1 ); + hud.menu[ 26 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 45, 1 ); + hud.menu[ 27 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 55, 1 ); + x_offset = 100; + hud.menu[ 28 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 80, 1 ); + hud.menu[ 29 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 90, 1 ); + hud.menu[ 30 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 100, 1 ); + hud.menu[ 31 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 110, 1 ); + hud.menu[ 32 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 120, 1 ); + hud.menu[ 33 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 145, 1 ); + hud.menu[ 34 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 155, 1 ); + hud.menu[ 35 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 180, 1 ); + hud.menu[ 36 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 190, 1 ); + x_offset = 65; + hud.menu[ 37 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 215, 1 ); + hud.menu[ 38 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 225, 1 ); + hud.menu[ 39 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 235, 1 ); + hud.menu[ 40 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 245, 1 ); + hud.menu[ 41 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 255, 1 ); + hud.menu[ 42 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 265, 1 ); + hud.menu[ 43 ] = maps/mp/gametypes/_dev::new_hud( menu_name, "", x + x_offset, y + 275, 1 ); + return hud; +#/ +} + +color( value ) +{ +/# + r = 1; + g = 1; + b = 0; + color = ( 0, 0, 0 ); + if ( value > 0 ) + { + r -= value; + } + else + { + g += value; + } + c = ( r, g, b ); + return c; +#/ +} + +dev_cac_gdt_update_think() +{ +/# + for ( ;; ) + { + level waittill( "gdt_update", asset, keyvalue ); + keyvalue = strtok( keyvalue, "\\" ); + key = keyvalue[ 0 ]; + switch( key ) + { + case "armorBullet": + key = "armor_bullet"; + break; + case "armorExplosive": + key = "armor_explosive"; + break; + case "moveSpeed": + key = "mobility"; + break; + case "sprintTimeTotal": + key = "sprint_time_total"; + break; + case "sprintTimeCooldown": + key = "sprint_time_cooldown"; + break; + default: + key = undefined; + break; + } + if ( !isDefined( key ) ) + { + continue; + } + else + { + value = float( keyvalue[ 1 ] ); + level.cac_attributes[ key ][ asset ] = value; + players = get_players(); + i = 0; + while ( i < players.size ) + { + i++; + } + } +#/ + } +} + +sort_greatest( function, attribute, greatest ) +{ +/# + keys = getarraykeys( level.cac_functions[ function ] ); + greatest = keys[ 0 ]; + i = 0; + while ( i < keys.size ) + { + if ( level.cac_attributes[ attribute ][ keys[ i ] ] > level.cac_attributes[ attribute ][ greatest ] ) + { + greatest = keys[ i ]; + } + i++; + } + return greatest; +#/ +} + +sort_least( function, attribute, least ) +{ +/# + keys = getarraykeys( level.cac_functions[ function ] ); + least = keys[ 0 ]; + i = 0; + while ( i < keys.size ) + { + if ( level.cac_attributes[ attribute ][ keys[ i ] ] < level.cac_attributes[ attribute ][ least ] ) + { + least = keys[ i ]; + } + i++; + } + return least; +#/ +} + +dev_cac_set_model_range( sort_function, attribute ) +{ +/# + if ( !dev_cac_player_valid() ) + { + return; + } + player = level.dev_cac_player; + player.cac_body_type = [[ sort_function ]]( "set_body_model", attribute ); + player.cac_head_type = [[ sort_function ]]( "set_head_model", attribute ); + player.cac_hat_type = [[ sort_function ]]( "set_hat_model", attribute ); + player dev_cac_set_player_model(); +#/ +} diff --git a/patch_mp/maps/mp/gametypes/_friendicons.gsc b/patch_mp/maps/mp/gametypes/_friendicons.gsc new file mode 100644 index 0000000..4d3f2c2 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_friendicons.gsc @@ -0,0 +1,113 @@ + +init() +{ + if ( level.createfx_enabled || sessionmodeiszombiesgame() ) + { + return; + } + if ( getDvar( "scr_drawfriend" ) == "" ) + { + setdvar( "scr_drawfriend", "0" ); + } + level.drawfriend = getDvarInt( "scr_drawfriend" ); +/# + assert( isDefined( game[ "headicon_allies" ] ), "Allied head icons are not defined. Check the team set for the level." ); +#/ +/# + assert( isDefined( game[ "headicon_axis" ] ), "Axis head icons are not defined. Check the team set for the level." ); +#/ + precacheheadicon( game[ "headicon_allies" ] ); + precacheheadicon( game[ "headicon_axis" ] ); + level thread onplayerconnect(); + for ( ;; ) + { + updatefriendiconsettings(); + wait 5; + } +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onplayerspawned(); + player thread onplayerkilled(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread showfriendicon(); + } +} + +onplayerkilled() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "killed_player" ); + self.headicon = ""; + } +} + +showfriendicon() +{ + if ( level.drawfriend ) + { + team = self.pers[ "team" ]; + self.headicon = game[ "headicon_" + team ]; + self.headiconteam = team; + } +} + +updatefriendiconsettings() +{ + drawfriend = getDvarFloat( "scr_drawfriend" ); + if ( level.drawfriend != drawfriend ) + { + level.drawfriend = drawfriend; + updatefriendicons(); + } +} + +updatefriendicons() +{ + players = level.players; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + while ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] != "spectator" && player.sessionstate == "playing" ) + { + if ( level.drawfriend ) + { + team = self.pers[ "team" ]; + self.headicon = game[ "headicon_" + team ]; + self.headiconteam = team; + i++; + continue; + } + else + { + players = level.players; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] != "spectator" && player.sessionstate == "playing" ) + { + player.headicon = ""; + } + i++; + } + } + } + i++; + } +} diff --git a/patch_mp/maps/mp/gametypes/_gameobjects.gsc b/patch_mp/maps/mp/gametypes/_gameobjects.gsc new file mode 100644 index 0000000..d5054cd --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globalentities.gsc b/patch_mp/maps/mp/gametypes/_globalentities.gsc new file mode 100644 index 0000000..e69de29 diff --git a/patch_mp/maps/mp/gametypes/_globallogic.gsc b/patch_mp/maps/mp/gametypes/_globallogic.gsc new file mode 100644 index 0000000..7f3452b --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globallogic_actor.gsc b/patch_mp/maps/mp/gametypes/_globallogic_actor.gsc new file mode 100644 index 0000000..08518fb --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globallogic_audio.gsc b/patch_mp/maps/mp/gametypes/_globallogic_audio.gsc new file mode 100644 index 0000000..2618bd9 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globallogic_defaults.gsc b/patch_mp/maps/mp/gametypes/_globallogic_defaults.gsc new file mode 100644 index 0000000..059642d --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globallogic_player.gsc b/patch_mp/maps/mp/gametypes/_globallogic_player.gsc new file mode 100644 index 0000000..2de5b99 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globallogic_score.gsc b/patch_mp/maps/mp/gametypes/_globallogic_score.gsc new file mode 100644 index 0000000..a5610a2 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globallogic_spawn.gsc b/patch_mp/maps/mp/gametypes/_globallogic_spawn.gsc new file mode 100644 index 0000000..fd882a8 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globallogic_ui.gsc b/patch_mp/maps/mp/gametypes/_globallogic_ui.gsc new file mode 100644 index 0000000..00d91fe --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globallogic_utils.gsc b/patch_mp/maps/mp/gametypes/_globallogic_utils.gsc new file mode 100644 index 0000000..4de74a7 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_globallogic_vehicle.gsc b/patch_mp/maps/mp/gametypes/_globallogic_vehicle.gsc new file mode 100644 index 0000000..9bfb41d --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_gv_actions.gsc b/patch_mp/maps/mp/gametypes/_gv_actions.gsc new file mode 100644 index 0000000..0b42480 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_healthoverlay.gsc b/patch_mp/maps/mp/gametypes/_healthoverlay.gsc new file mode 100644 index 0000000..a7d8f4b --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_hostmigration.gsc b/patch_mp/maps/mp/gametypes/_hostmigration.gsc new file mode 100644 index 0000000..7eca73c --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_hud.gsc b/patch_mp/maps/mp/gametypes/_hud.gsc new file mode 100644 index 0000000..529ea3f --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_hud_message.gsc b/patch_mp/maps/mp/gametypes/_hud_message.gsc new file mode 100644 index 0000000..2425d13 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_hud_util.gsc b/patch_mp/maps/mp/gametypes/_hud_util.gsc new file mode 100644 index 0000000..16b74f2 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_killcam.gsc b/patch_mp/maps/mp/gametypes/_killcam.gsc new file mode 100644 index 0000000..5cf76fb --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_killcam.gsc @@ -0,0 +1,789 @@ +#include maps/mp/gametypes/_globallogic_spawn; +#include maps/mp/gametypes/_spectating; +#include maps/mp/_tacticalinsertion; +#include maps/mp/_challenges; +#include maps/mp/gametypes/_globallogic; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +init() +{ + precachestring( &"PLATFORM_PRESS_TO_SKIP" ); + precachestring( &"PLATFORM_PRESS_TO_RESPAWN" ); + precacheshader( "white" ); + level.killcam = getgametypesetting( "allowKillcam" ); + level.finalkillcam = getgametypesetting( "allowFinalKillcam" ); + initfinalkillcam(); +} + +initfinalkillcam() +{ + level.finalkillcamsettings = []; + initfinalkillcamteam( "none" ); + _a23 = level.teams; + _k23 = getFirstArrayKey( _a23 ); + while ( isDefined( _k23 ) ) + { + team = _a23[ _k23 ]; + initfinalkillcamteam( team ); + _k23 = getNextArrayKey( _a23, _k23 ); + } + level.finalkillcam_winner = undefined; +} + +initfinalkillcamteam( team ) +{ + level.finalkillcamsettings[ team ] = spawnstruct(); + clearfinalkillcamteam( team ); +} + +clearfinalkillcamteam( team ) +{ + level.finalkillcamsettings[ team ].spectatorclient = undefined; + level.finalkillcamsettings[ team ].weapon = undefined; + level.finalkillcamsettings[ team ].deathtime = undefined; + level.finalkillcamsettings[ team ].deathtimeoffset = undefined; + level.finalkillcamsettings[ team ].offsettime = undefined; + level.finalkillcamsettings[ team ].entityindex = undefined; + level.finalkillcamsettings[ team ].targetentityindex = undefined; + level.finalkillcamsettings[ team ].entitystarttime = undefined; + level.finalkillcamsettings[ team ].perks = undefined; + level.finalkillcamsettings[ team ].killstreaks = undefined; + level.finalkillcamsettings[ team ].attacker = undefined; +} + +recordkillcamsettings( spectatorclient, targetentityindex, sweapon, deathtime, deathtimeoffset, offsettime, entityindex, entitystarttime, perks, killstreaks, attacker ) +{ + if ( level.teambased && isDefined( attacker.team ) && isDefined( level.teams[ attacker.team ] ) ) + { + team = attacker.team; + level.finalkillcamsettings[ team ].spectatorclient = spectatorclient; + level.finalkillcamsettings[ team ].weapon = sweapon; + level.finalkillcamsettings[ team ].deathtime = deathtime; + level.finalkillcamsettings[ team ].deathtimeoffset = deathtimeoffset; + level.finalkillcamsettings[ team ].offsettime = offsettime; + level.finalkillcamsettings[ team ].entityindex = entityindex; + level.finalkillcamsettings[ team ].targetentityindex = targetentityindex; + level.finalkillcamsettings[ team ].entitystarttime = entitystarttime; + level.finalkillcamsettings[ team ].perks = perks; + level.finalkillcamsettings[ team ].killstreaks = killstreaks; + level.finalkillcamsettings[ team ].attacker = attacker; + } + level.finalkillcamsettings[ "none" ].spectatorclient = spectatorclient; + level.finalkillcamsettings[ "none" ].weapon = sweapon; + level.finalkillcamsettings[ "none" ].deathtime = deathtime; + level.finalkillcamsettings[ "none" ].deathtimeoffset = deathtimeoffset; + level.finalkillcamsettings[ "none" ].offsettime = offsettime; + level.finalkillcamsettings[ "none" ].entityindex = entityindex; + level.finalkillcamsettings[ "none" ].targetentityindex = targetentityindex; + level.finalkillcamsettings[ "none" ].entitystarttime = entitystarttime; + level.finalkillcamsettings[ "none" ].perks = perks; + level.finalkillcamsettings[ "none" ].killstreaks = killstreaks; + level.finalkillcamsettings[ "none" ].attacker = attacker; +} + +erasefinalkillcam() +{ + clearfinalkillcamteam( "none" ); + _a89 = level.teams; + _k89 = getFirstArrayKey( _a89 ); + while ( isDefined( _k89 ) ) + { + team = _a89[ _k89 ]; + clearfinalkillcamteam( team ); + _k89 = getNextArrayKey( _a89, _k89 ); + } + level.finalkillcam_winner = undefined; +} + +finalkillcamwaiter() +{ + if ( !isDefined( level.finalkillcam_winner ) ) + { + return 0; + } + level waittill( "final_killcam_done" ); + return 1; +} + +postroundfinalkillcam() +{ + if ( isDefined( level.sidebet ) && level.sidebet ) + { + return; + } + level notify( "play_final_killcam" ); + maps/mp/gametypes/_globallogic::resetoutcomeforallplayers(); + finalkillcamwaiter(); +} + +dofinalkillcam() +{ + level waittill( "play_final_killcam" ); + level.infinalkillcam = 1; + winner = "none"; + if ( isDefined( level.finalkillcam_winner ) ) + { + winner = level.finalkillcam_winner; + } + if ( !isDefined( level.finalkillcamsettings[ winner ].targetentityindex ) ) + { + level.infinalkillcam = 0; + level notify( "final_killcam_done" ); + return; + } + if ( isDefined( level.finalkillcamsettings[ winner ].attacker ) ) + { + maps/mp/_challenges::getfinalkill( level.finalkillcamsettings[ winner ].attacker ); + } + visionsetnaked( getDvar( "mapname" ), 0 ); + players = level.players; + index = 0; + while ( index < players.size ) + { + player = players[ index ]; + player closemenu(); + player closeingamemenu(); + player thread finalkillcam( winner ); + index++; + } + wait 0,1; + while ( areanyplayerswatchingthekillcam() ) + { + wait 0,05; + } + level notify( "final_killcam_done" ); + level.infinalkillcam = 0; +} + +startlastkillcam() +{ +} + +areanyplayerswatchingthekillcam() +{ + players = level.players; + index = 0; + while ( index < players.size ) + { + player = players[ index ]; + if ( isDefined( player.killcam ) ) + { + return 1; + } + index++; + } + return 0; +} + +killcam( attackernum, targetnum, killcamentity, killcamentityindex, killcamentitystarttime, sweapon, deathtime, deathtimeoffset, offsettime, respawn, maxtime, perks, killstreaks, attacker ) +{ + self endon( "disconnect" ); + self endon( "spawned" ); + level endon( "game_ended" ); + if ( attackernum < 0 ) + { + return; + } + postdeathdelay = ( getTime() - deathtime ) / 1000; + predelay = postdeathdelay + deathtimeoffset; + camtime = calckillcamtime( sweapon, killcamentitystarttime, predelay, respawn, maxtime ); + postdelay = calcpostdelay(); + killcamlength = camtime + postdelay; + if ( isDefined( maxtime ) && killcamlength > maxtime ) + { + if ( maxtime < 2 ) + { + return; + } + if ( ( maxtime - camtime ) >= 1 ) + { + postdelay = maxtime - camtime; + } + else + { + postdelay = 1; + camtime = maxtime - 1; + } + killcamlength = camtime + postdelay; + } + killcamoffset = camtime + predelay; + self notify( "begin_killcam" ); + killcamstarttime = getTime() - ( killcamoffset * 1000 ); + self.sessionstate = "spectator"; + self.spectatorclient = attackernum; + self.killcamentity = -1; + if ( killcamentityindex >= 0 ) + { + self thread setkillcamentity( killcamentityindex, killcamentitystarttime - killcamstarttime - 100 ); + } + self.killcamtargetentity = targetnum; + self.archivetime = killcamoffset; + self.killcamlength = killcamlength; + self.psoffsettime = offsettime; + recordkillcamsettings( attackernum, targetnum, sweapon, deathtime, deathtimeoffset, offsettime, killcamentityindex, killcamentitystarttime, perks, killstreaks, attacker ); + _a268 = level.teams; + _k268 = getFirstArrayKey( _a268 ); + while ( isDefined( _k268 ) ) + { + team = _a268[ _k268 ]; + self allowspectateteam( team, 1 ); + _k268 = getNextArrayKey( _a268, _k268 ); + } + self allowspectateteam( "freelook", 1 ); + self allowspectateteam( "none", 1 ); + self thread endedkillcamcleanup(); + wait 0,05; + if ( self.archivetime <= predelay ) + { + self.sessionstate = "dead"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self notify( "end_killcam" ); + return; + } + self thread checkforabruptkillcamend(); + self.killcam = 1; + self addkillcamskiptext( respawn ); + if ( !self issplitscreen() && level.perksenabled == 1 ) + { + self addkillcamtimer( camtime ); + self maps/mp/gametypes/_hud_util::showperks(); + } + self thread spawnedkillcamcleanup(); + self thread waitskipkillcambutton(); + self thread waitteamchangeendkillcam(); + self thread waitkillcamtime(); + self thread maps/mp/_tacticalinsertion::cancel_button_think(); + self waittill( "end_killcam" ); + self endkillcam( 0 ); + self.sessionstate = "dead"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; +} + +setkillcamentity( killcamentityindex, delayms ) +{ + self endon( "disconnect" ); + self endon( "end_killcam" ); + self endon( "spawned" ); + if ( delayms > 0 ) + { + wait ( delayms / 1000 ); + } + self.killcamentity = killcamentityindex; +} + +waitkillcamtime() +{ + self endon( "disconnect" ); + self endon( "end_killcam" ); + wait ( self.killcamlength - 0,05 ); + self notify( "end_killcam" ); +} + +waitfinalkillcamslowdown( deathtime, starttime ) +{ + self endon( "disconnect" ); + self endon( "end_killcam" ); + secondsuntildeath = ( deathtime - starttime ) / 1000; + deathtime = getTime() + ( secondsuntildeath * 1000 ); + waitbeforedeath = 2; + maps/mp/_utility::setclientsysstate( "levelNotify", "fkcb" ); + wait max( 0, secondsuntildeath - waitbeforedeath ); + setslowmotion( 1, 0,25, waitbeforedeath ); + wait ( waitbeforedeath + 0,5 ); + setslowmotion( 0,25, 1, 1 ); + wait 0,5; + maps/mp/_utility::setclientsysstate( "levelNotify", "fkce" ); +} + +waitskipkillcambutton() +{ + self endon( "disconnect" ); + self endon( "end_killcam" ); + while ( self usebuttonpressed() ) + { + wait 0,05; + } + while ( !self usebuttonpressed() ) + { + wait 0,05; + } + self notify( "end_killcam" ); + self clientnotify( "fkce" ); +} + +waitteamchangeendkillcam() +{ + self endon( "disconnect" ); + self endon( "end_killcam" ); + self waittill( "changed_class" ); + endkillcam( 0 ); +} + +waitskipkillcamsafespawnbutton() +{ + self endon( "disconnect" ); + self endon( "end_killcam" ); + while ( self fragbuttonpressed() ) + { + wait 0,05; + } + while ( !self fragbuttonpressed() ) + { + wait 0,05; + } + self.wantsafespawn = 1; + self notify( "end_killcam" ); +} + +endkillcam( final ) +{ + if ( isDefined( self.kc_skiptext ) ) + { + self.kc_skiptext.alpha = 0; + } + if ( isDefined( self.kc_timer ) ) + { + self.kc_timer.alpha = 0; + } + self.killcam = undefined; + if ( !self issplitscreen() ) + { + self hideallperks(); + } + self thread maps/mp/gametypes/_spectating::setspectatepermissions(); +} + +checkforabruptkillcamend() +{ + self endon( "disconnect" ); + self endon( "end_killcam" ); + while ( 1 ) + { + if ( self.archivetime <= 0 ) + { + break; + } + else + { + wait 0,05; + } + } + self notify( "end_killcam" ); +} + +spawnedkillcamcleanup() +{ + self endon( "end_killcam" ); + self endon( "disconnect" ); + self waittill( "spawned" ); + self endkillcam( 0 ); +} + +spectatorkillcamcleanup( attacker ) +{ + self endon( "end_killcam" ); + self endon( "disconnect" ); + attacker endon( "disconnect" ); + attacker waittill( "begin_killcam", attackerkcstarttime ); + waittime = max( 0, attackerkcstarttime - self.deathtime - 50 ); + wait waittime; + self endkillcam( 0 ); +} + +endedkillcamcleanup() +{ + self endon( "end_killcam" ); + self endon( "disconnect" ); + level waittill( "game_ended" ); + self endkillcam( 0 ); +} + +endedfinalkillcamcleanup() +{ + self endon( "end_killcam" ); + self endon( "disconnect" ); + level waittill( "game_ended" ); + self endkillcam( 1 ); +} + +cancelkillcamusebutton() +{ + return self usebuttonpressed(); +} + +cancelkillcamsafespawnbutton() +{ + return self fragbuttonpressed(); +} + +cancelkillcamcallback() +{ + self.cancelkillcam = 1; +} + +cancelkillcamsafespawncallback() +{ + self.cancelkillcam = 1; + self.wantsafespawn = 1; +} + +cancelkillcamonuse() +{ + self thread cancelkillcamonuse_specificbutton( ::cancelkillcamusebutton, ::cancelkillcamcallback ); +} + +cancelkillcamonuse_specificbutton( pressingbuttonfunc, finishedfunc ) +{ + self endon( "death_delay_finished" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + for ( ;; ) + { + if ( !( self [[ pressingbuttonfunc ]]() ) ) + { + wait 0,05; + continue; + } + else buttontime = 0; + while ( self [[ pressingbuttonfunc ]]() ) + { + buttontime += 0,05; + wait 0,05; + } + if ( buttontime >= 0,5 ) + { + continue; + } + else buttontime = 0; + while ( !( self [[ pressingbuttonfunc ]]() ) && buttontime < 0,5 ) + { + buttontime += 0,05; + wait 0,05; + } + if ( buttontime >= 0,5 ) + { + continue; + } + else + { + self [[ finishedfunc ]](); + return; + } + } +} + +finalkillcam( winner ) +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + if ( waslastround() ) + { + setmatchflag( "final_killcam", 1 ); + setmatchflag( "round_end_killcam", 0 ); + } + else + { + setmatchflag( "final_killcam", 0 ); + setmatchflag( "round_end_killcam", 1 ); + } +/# + if ( getDvarInt( "scr_force_finalkillcam" ) == 1 ) + { + setmatchflag( "final_killcam", 1 ); + setmatchflag( "round_end_killcam", 0 ); +#/ + } + if ( level.console ) + { + self maps/mp/gametypes/_globallogic_spawn::setthirdperson( 0 ); + } + killcamsettings = level.finalkillcamsettings[ winner ]; + postdeathdelay = ( getTime() - killcamsettings.deathtime ) / 1000; + predelay = postdeathdelay + killcamsettings.deathtimeoffset; + camtime = calckillcamtime( killcamsettings.weapon, killcamsettings.entitystarttime, predelay, 0, undefined ); + postdelay = calcpostdelay(); + killcamoffset = camtime + predelay; + killcamlength = ( camtime + postdelay ) - 0,05; + killcamstarttime = getTime() - ( killcamoffset * 1000 ); + self notify( "begin_killcam" ); + self.sessionstate = "spectator"; + self.spectatorclient = killcamsettings.spectatorclient; + self.killcamentity = -1; + if ( killcamsettings.entityindex >= 0 ) + { + self thread setkillcamentity( killcamsettings.entityindex, killcamsettings.entitystarttime - killcamstarttime - 100 ); + } + self.killcamtargetentity = killcamsettings.targetentityindex; + self.archivetime = killcamoffset; + self.killcamlength = killcamlength; + self.psoffsettime = killcamsettings.offsettime; + _a613 = level.teams; + _k613 = getFirstArrayKey( _a613 ); + while ( isDefined( _k613 ) ) + { + team = _a613[ _k613 ]; + self allowspectateteam( team, 1 ); + _k613 = getNextArrayKey( _a613, _k613 ); + } + self allowspectateteam( "freelook", 1 ); + self allowspectateteam( "none", 1 ); + self thread endedfinalkillcamcleanup(); + wait 0,05; + if ( self.archivetime <= predelay ) + { + self.sessionstate = "dead"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self notify( "end_killcam" ); + return; + } + self thread checkforabruptkillcamend(); + self.killcam = 1; + if ( !self issplitscreen() ) + { + self addkillcamtimer( camtime ); + } + self thread waitkillcamtime(); + self thread waitfinalkillcamslowdown( level.finalkillcamsettings[ winner ].deathtime, killcamstarttime ); + self waittill( "end_killcam" ); + self endkillcam( 1 ); + setmatchflag( "final_killcam", 0 ); + setmatchflag( "round_end_killcam", 0 ); + self spawnendoffinalkillcam(); +} + +spawnendoffinalkillcam() +{ + [[ level.spawnspectator ]](); + self freezecontrols( 1 ); +} + +iskillcamentityweapon( sweapon ) +{ + if ( sweapon == "planemortar_mp" ) + { + return 1; + } + return 0; +} + +iskillcamgrenadeweapon( sweapon ) +{ + if ( sweapon == "frag_grenade_mp" ) + { + return 1; + } + else + { + if ( sweapon == "frag_grenade_short_mp" ) + { + return 1; + } + else + { + if ( sweapon == "sticky_grenade_mp" ) + { + return 1; + } + else + { + if ( sweapon == "tabun_gas_mp" ) + { + return 1; + } + } + } + } + return 0; +} + +calckillcamtime( sweapon, entitystarttime, predelay, respawn, maxtime ) +{ + camtime = 0; + if ( getDvar( #"C45D9077" ) == "" ) + { + if ( iskillcamentityweapon( sweapon ) ) + { + camtime = ( ( getTime() - entitystarttime ) / 1000 ) - predelay - 0,1; + } + else if ( !respawn ) + { + camtime = 5; + } + else if ( iskillcamgrenadeweapon( sweapon ) ) + { + camtime = 4,25; + } + else + { + camtime = 2,5; + } + } + else + { + camtime = getDvarFloat( #"C45D9077" ); + } + if ( isDefined( maxtime ) ) + { + if ( camtime > maxtime ) + { + camtime = maxtime; + } + if ( camtime < 0,05 ) + { + camtime = 0,05; + } + } + return camtime; +} + +calcpostdelay() +{ + postdelay = 0; + if ( getDvar( #"0D34D95D" ) == "" ) + { + postdelay = 2; + } + else + { + postdelay = getDvarFloat( #"0D34D95D" ); + if ( postdelay < 0,05 ) + { + postdelay = 0,05; + } + } + return postdelay; +} + +addkillcamskiptext( respawn ) +{ + if ( !isDefined( self.kc_skiptext ) ) + { + self.kc_skiptext = newclienthudelem( self ); + self.kc_skiptext.archived = 0; + self.kc_skiptext.x = 0; + self.kc_skiptext.alignx = "center"; + self.kc_skiptext.aligny = "middle"; + self.kc_skiptext.horzalign = "center"; + self.kc_skiptext.vertalign = "bottom"; + self.kc_skiptext.sort = 1; + self.kc_skiptext.font = "objective"; + } + if ( self issplitscreen() ) + { + self.kc_skiptext.y = -100; + self.kc_skiptext.fontscale = 1,4; + } + else + { + self.kc_skiptext.y = -120; + self.kc_skiptext.fontscale = 2; + } + if ( respawn ) + { + self.kc_skiptext settext( &"PLATFORM_PRESS_TO_RESPAWN" ); + } + else + { + self.kc_skiptext settext( &"PLATFORM_PRESS_TO_SKIP" ); + } + self.kc_skiptext.alpha = 1; +} + +addkillcamtimer( camtime ) +{ +} + +initkcelements() +{ + if ( !isDefined( self.kc_skiptext ) ) + { + self.kc_skiptext = newclienthudelem( self ); + self.kc_skiptext.archived = 0; + self.kc_skiptext.x = 0; + self.kc_skiptext.alignx = "center"; + self.kc_skiptext.aligny = "top"; + self.kc_skiptext.horzalign = "center_adjustable"; + self.kc_skiptext.vertalign = "top_adjustable"; + self.kc_skiptext.sort = 1; + self.kc_skiptext.font = "default"; + self.kc_skiptext.foreground = 1; + self.kc_skiptext.hidewheninmenu = 1; + if ( self issplitscreen() ) + { + self.kc_skiptext.y = 20; + self.kc_skiptext.fontscale = 1,2; + } + else + { + self.kc_skiptext.y = 32; + self.kc_skiptext.fontscale = 1,8; + } + } + if ( !isDefined( self.kc_othertext ) ) + { + self.kc_othertext = newclienthudelem( self ); + self.kc_othertext.archived = 0; + self.kc_othertext.y = 48; + self.kc_othertext.alignx = "left"; + self.kc_othertext.aligny = "top"; + self.kc_othertext.horzalign = "center"; + self.kc_othertext.vertalign = "middle"; + self.kc_othertext.sort = 10; + self.kc_othertext.font = "small"; + self.kc_othertext.foreground = 1; + self.kc_othertext.hidewheninmenu = 1; + if ( self issplitscreen() ) + { + self.kc_othertext.x = 16; + self.kc_othertext.fontscale = 1,2; + } + else + { + self.kc_othertext.x = 32; + self.kc_othertext.fontscale = 1,6; + } + } + if ( !isDefined( self.kc_icon ) ) + { + self.kc_icon = newclienthudelem( self ); + self.kc_icon.archived = 0; + self.kc_icon.x = 16; + self.kc_icon.y = 16; + self.kc_icon.alignx = "left"; + self.kc_icon.aligny = "top"; + self.kc_icon.horzalign = "center"; + self.kc_icon.vertalign = "middle"; + self.kc_icon.sort = 1; + self.kc_icon.foreground = 1; + self.kc_icon.hidewheninmenu = 1; + } + if ( !self issplitscreen() ) + { + if ( !isDefined( self.kc_timer ) ) + { + self.kc_timer = createfontstring( "hudbig", 1 ); + self.kc_timer.archived = 0; + self.kc_timer.x = 0; + self.kc_timer.alignx = "center"; + self.kc_timer.aligny = "middle"; + self.kc_timer.horzalign = "center_safearea"; + self.kc_timer.vertalign = "top_adjustable"; + self.kc_timer.y = 42; + self.kc_timer.sort = 1; + self.kc_timer.font = "hudbig"; + self.kc_timer.foreground = 1; + self.kc_timer.color = vectorScale( ( 1, 1, 1 ), 0,85 ); + self.kc_timer.hidewheninmenu = 1; + } + } +} diff --git a/patch_mp/maps/mp/gametypes/_menus.gsc b/patch_mp/maps/mp/gametypes/_menus.gsc new file mode 100644 index 0000000..97f9513 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_objpoints.gsc b/patch_mp/maps/mp/gametypes/_objpoints.gsc new file mode 100644 index 0000000..15c582f --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_objpoints.gsc @@ -0,0 +1,175 @@ +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +init() +{ + precacheshader( "objpoint_default" ); + level.objpointnames = []; + level.objpoints = []; + if ( level.splitscreen ) + { + level.objpointsize = 15; + } + else + { + level.objpointsize = 8; + } + level.objpoint_alpha_default = 0,5; + level.objpointscale = 1; +} + +createteamobjpoint( name, origin, team, shader, alpha, scale ) +{ +/# + if ( !isDefined( level.teams[ team ] ) ) + { + assert( team == "all" ); + } +#/ + objpoint = getobjpointbyname( name ); + if ( isDefined( objpoint ) ) + { + deleteobjpoint( objpoint ); + } + if ( !isDefined( shader ) ) + { + shader = "objpoint_default"; + } + if ( !isDefined( scale ) ) + { + scale = 1; + } + if ( team != "all" ) + { + objpoint = newteamhudelem( team ); + } + else + { + objpoint = newhudelem(); + } + objpoint.name = name; + objpoint.x = origin[ 0 ]; + objpoint.y = origin[ 1 ]; + objpoint.z = origin[ 2 ]; + objpoint.team = team; + objpoint.isflashing = 0; + objpoint.isshown = 1; + objpoint.fadewhentargeted = 1; + objpoint.archived = 0; + objpoint setshader( shader, level.objpointsize, level.objpointsize ); + objpoint setwaypoint( 1 ); + if ( isDefined( alpha ) ) + { + objpoint.alpha = alpha; + } + else + { + objpoint.alpha = level.objpoint_alpha_default; + } + objpoint.basealpha = objpoint.alpha; + objpoint.index = level.objpointnames.size; + level.objpoints[ name ] = objpoint; + level.objpointnames[ level.objpointnames.size ] = name; + return objpoint; +} + +deleteobjpoint( oldobjpoint ) +{ +/# + assert( level.objpoints.size == level.objpointnames.size ); +#/ + if ( level.objpoints.size == 1 ) + { +/# + assert( level.objpointnames[ 0 ] == oldobjpoint.name ); +#/ +/# + assert( isDefined( level.objpoints[ oldobjpoint.name ] ) ); +#/ + level.objpoints = []; + level.objpointnames = []; + oldobjpoint destroy(); + return; + } + newindex = oldobjpoint.index; + oldindex = level.objpointnames.size - 1; + objpoint = getobjpointbyindex( oldindex ); + level.objpointnames[ newindex ] = objpoint.name; + objpoint.index = newindex; + oldobjpoint destroy(); +} + +updateorigin( origin ) +{ + if ( self.x != origin[ 0 ] ) + { + self.x = origin[ 0 ]; + } + if ( self.y != origin[ 1 ] ) + { + self.y = origin[ 1 ]; + } + if ( self.z != origin[ 2 ] ) + { + self.z = origin[ 2 ]; + } +} + +setoriginbyname( name, origin ) +{ + objpoint = getobjpointbyname( name ); + objpoint updateorigin( origin ); +} + +getobjpointbyname( name ) +{ + if ( isDefined( level.objpoints[ name ] ) ) + { + return level.objpoints[ name ]; + } + else + { + return undefined; + } +} + +getobjpointbyindex( index ) +{ + if ( isDefined( level.objpointnames[ index ] ) ) + { + return level.objpoints[ level.objpointnames[ index ] ]; + } + else + { + return undefined; + } +} + +startflashing() +{ + self endon( "stop_flashing_thread" ); + if ( self.isflashing ) + { + return; + } + self.isflashing = 1; + while ( self.isflashing ) + { + self fadeovertime( 0,75 ); + self.alpha = 0,35 * self.basealpha; + wait 0,75; + self fadeovertime( 0,75 ); + self.alpha = self.basealpha; + wait 0,75; + } + self.alpha = self.basealpha; +} + +stopflashing() +{ + if ( !self.isflashing ) + { + return; + } + self.isflashing = 0; +} diff --git a/patch_mp/maps/mp/gametypes/_perplayer.gsc b/patch_mp/maps/mp/gametypes/_perplayer.gsc new file mode 100644 index 0000000..1fd16a2 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_persistence.gsc b/patch_mp/maps/mp/gametypes/_persistence.gsc new file mode 100644 index 0000000..a7dbbb4 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_persistence.gsc @@ -0,0 +1,499 @@ +#include maps/mp/gametypes/_persistence; +#include maps/mp/gametypes/_globallogic; +#include maps/mp/bots/_bot; +#include maps/mp/_utility; + +init() +{ + level.persistentdatainfo = []; + level.maxrecentstats = 10; + level.maxhitlocations = 19; + maps/mp/gametypes/_class::init(); + maps/mp/gametypes/_rank::init(); + level thread maps/mp/_challenges::init(); + level thread maps/mp/_medals::init(); + level thread maps/mp/_scoreevents::init(); + maps/mp/_popups::init(); + level thread onplayerconnect(); + level thread initializestattracking(); + level thread uploadglobalstatcounters(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player.enabletext = 1; + } +} + +initializestattracking() +{ + level.globalexecutions = 0; + level.globalchallenges = 0; + level.globalsharepackages = 0; + level.globalcontractsfailed = 0; + level.globalcontractspassed = 0; + level.globalcontractscppaid = 0; + level.globalkillstreakscalled = 0; + level.globalkillstreaksdestroyed = 0; + level.globalkillstreaksdeathsfrom = 0; + level.globallarryskilled = 0; + level.globalbuzzkills = 0; + level.globalrevives = 0; + level.globalafterlifes = 0; + level.globalcomebacks = 0; + level.globalpaybacks = 0; + level.globalbackstabs = 0; + level.globalbankshots = 0; + level.globalskewered = 0; + level.globalteammedals = 0; + level.globalfeetfallen = 0; + level.globaldistancesprinted = 0; + level.globaldembombsprotected = 0; + level.globaldembombsdestroyed = 0; + level.globalbombsdestroyed = 0; + level.globalfraggrenadesfired = 0; + level.globalsatchelchargefired = 0; + level.globalshotsfired = 0; + level.globalcrossbowfired = 0; + level.globalcarsdestroyed = 0; + level.globalbarrelsdestroyed = 0; + level.globalbombsdestroyedbyteam = []; + _a67 = level.teams; + _k67 = getFirstArrayKey( _a67 ); + while ( isDefined( _k67 ) ) + { + team = _a67[ _k67 ]; + level.globalbombsdestroyedbyteam[ team ] = 0; + _k67 = getNextArrayKey( _a67, _k67 ); + } +} + +uploadglobalstatcounters() +{ + level waittill( "game_ended" ); + if ( !level.rankedmatch && !level.wagermatch ) + { + return; + } + totalkills = 0; + totaldeaths = 0; + totalassists = 0; + totalheadshots = 0; + totalsuicides = 0; + totaltimeplayed = 0; + totalflagscaptured = 0; + totalflagsreturned = 0; + totalhqsdestroyed = 0; + totalhqscaptured = 0; + totalsddefused = 0; + totalsdplants = 0; + totalhumiliations = 0; + totalsabdestroyedbyteam = []; + _a95 = level.teams; + _k95 = getFirstArrayKey( _a95 ); + while ( isDefined( _k95 ) ) + { + team = _a95[ _k95 ]; + totalsabdestroyedbyteam[ team ] = 0; + _k95 = getNextArrayKey( _a95, _k95 ); + } + switch( level.gametype ) + { + case "dem": + bombzonesleft = 0; + index = 0; + while ( index < level.bombzones.size ) + { + if ( !isDefined( level.bombzones[ index ].bombexploded ) || !level.bombzones[ index ].bombexploded ) + { + level.globaldembombsprotected++; + index++; + continue; + } + else + { + level.globaldembombsdestroyed++; + } + index++; + } + case "sab": + _a117 = level.teams; + _k117 = getFirstArrayKey( _a117 ); + while ( isDefined( _k117 ) ) + { + team = _a117[ _k117 ]; + totalsabdestroyedbyteam[ team ] = level.globalbombsdestroyedbyteam[ team ]; + _k117 = getNextArrayKey( _a117, _k117 ); + } + } + players = get_players(); + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + totaltimeplayed += min( player.timeplayed[ "total" ], level.timeplayedcap ); + i++; + } + incrementcounter( "global_executions", level.globalexecutions ); + incrementcounter( "global_sharedpackagemedals", level.globalsharepackages ); + incrementcounter( "global_dem_bombsdestroyed", level.globaldembombsdestroyed ); + incrementcounter( "global_dem_bombsprotected", level.globaldembombsprotected ); + incrementcounter( "global_contracts_failed", level.globalcontractsfailed ); + incrementcounter( "global_killstreaks_called", level.globalkillstreakscalled ); + incrementcounter( "global_killstreaks_destroyed", level.globalkillstreaksdestroyed ); + incrementcounter( "global_killstreaks_deathsfrom", level.globalkillstreaksdeathsfrom ); + incrementcounter( "global_buzzkills", level.globalbuzzkills ); + incrementcounter( "global_revives", level.globalrevives ); + incrementcounter( "global_afterlifes", level.globalafterlifes ); + incrementcounter( "global_comebacks", level.globalcomebacks ); + incrementcounter( "global_paybacks", level.globalpaybacks ); + incrementcounter( "global_backstabs", level.globalbackstabs ); + incrementcounter( "global_bankshots", level.globalbankshots ); + incrementcounter( "global_skewered", level.globalskewered ); + incrementcounter( "global_teammedals", level.globalteammedals ); + incrementcounter( "global_fraggrenadesthrown", level.globalfraggrenadesfired ); + incrementcounter( "global_c4thrown", level.globalsatchelchargefired ); + incrementcounter( "global_shotsfired", level.globalshotsfired ); + incrementcounter( "global_crossbowfired", level.globalcrossbowfired ); + incrementcounter( "global_carsdestroyed", level.globalcarsdestroyed ); + incrementcounter( "global_barrelsdestroyed", level.globalbarrelsdestroyed ); + incrementcounter( "global_challenges_finished", level.globalchallenges ); + incrementcounter( "global_contractscppaid", level.globalcontractscppaid ); + incrementcounter( "global_distancesprinted100inches", int( level.globaldistancesprinted ) ); + incrementcounter( "global_combattraining_botskilled", level.globallarryskilled ); + incrementcounter( "global_distancefeetfallen", int( level.globalfeetfallen ) ); + incrementcounter( "global_minutes", int( totaltimeplayed / 60 ) ); + if ( !waslastround() ) + { + return; + } + wait 0,05; + players = get_players(); + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + totalkills += player.kills; + totaldeaths += player.deaths; + totalassists += player.assists; + totalheadshots += player.headshots; + totalsuicides += player.suicides; + totalhumiliations += player.humiliated; + totaltimeplayed += int( min( player.timeplayed[ "alive" ], level.timeplayedcap ) ); + switch( level.gametype ) + { + case "ctf": + totalflagscaptured += player.captures; + totalflagsreturned += player.returns; + break; + i++; + continue; + case "koth": + totalhqsdestroyed += player.destructions; + totalhqscaptured += player.captures; + break; + i++; + continue; + case "sd": + totalsddefused += player.defuses; + totalsdplants += player.plants; + break; + i++; + continue; + case "sab": + if ( isDefined( player.team ) && isDefined( level.teams[ player.team ] ) ) + { + totalsabdestroyedbyteam[ player.team ] += player.destructions; + } + break; + i++; + continue; + } + i++; + } + if ( maps/mp/bots/_bot::is_bot_ranked_match() ) + { + incrementcounter( "global_combattraining_gamesplayed", 1 ); + } + incrementcounter( "global_kills", totalkills ); + incrementcounter( "global_deaths", totaldeaths ); + incrementcounter( "global_assists", totalassists ); + incrementcounter( "global_headshots", totalheadshots ); + incrementcounter( "global_suicides", totalsuicides ); + incrementcounter( "global_games", 1 ); + incrementcounter( "global_ctf_flagscaptured", totalflagscaptured ); + incrementcounter( "global_ctf_flagsreturned", totalflagsreturned ); + incrementcounter( "global_hq_destroyed", totalhqsdestroyed ); + incrementcounter( "global_hq_captured", totalhqscaptured ); + incrementcounter( "global_snd_defuses", totalsddefused ); + incrementcounter( "global_snd_plants", totalsdplants ); + incrementcounter( "global_sab_destroyedbyops", totalsabdestroyedbyteam[ "allies" ] ); + incrementcounter( "global_sab_destroyedbycommunists", totalsabdestroyedbyteam[ "axis" ] ); + incrementcounter( "global_humiliations", totalhumiliations ); + if ( isDefined( game[ "wager_pot" ] ) ) + { + incrementcounter( "global_wageredcp", game[ "wager_pot" ] ); + } + } + } +} + +statgetwithgametype( dataname ) +{ + if ( isDefined( level.nopersistence ) && level.nopersistence ) + { + return 0; + } + if ( !level.onlinegame ) + { + return 0; + } + return self getdstat( "PlayerStatsByGameType", getgametypename(), dataname, "StatValue" ); +} + +getgametypename() +{ + if ( !isDefined( level.fullgametypename ) ) + { + if ( isDefined( level.hardcoremode ) && level.hardcoremode && ispartygamemode() == 0 ) + { + prefix = "HC"; + } + else + { + prefix = ""; + } + level.fullgametypename = tolower( prefix + level.gametype ); + } + return level.fullgametypename; +} + +ispartygamemode() +{ + switch( level.gametype ) + { + case "gun": + case "oic": + case "sas": + case "shrp": + return 1; + } + return 0; + } +} + +isstatmodifiable( dataname ) +{ + if ( !level.rankedmatch ) + { + return level.wagermatch; + } +} + +statsetwithgametype( dataname, value, incvalue ) +{ + if ( isDefined( level.nopersistence ) && level.nopersistence ) + { + return 0; + } + if ( !isstatmodifiable( dataname ) ) + { + return; + } + if ( level.disablestattracking ) + { + return; + } + self setdstat( "PlayerStatsByGameType", getgametypename(), dataname, "StatValue", value ); +} + +adjustrecentstats() +{ +/# + if ( getDvarInt( "scr_writeConfigStrings" ) == 1 || getDvarInt( "scr_hostmigrationtest" ) == 1 ) + { + return; +#/ + } + initializematchstats(); +} + +getrecentstat( isglobal, index, statname ) +{ + if ( level.wagermatch ) + { + return self getdstat( "RecentEarnings", index, statname ); + } + else + { + if ( isglobal ) + { + modename = maps/mp/gametypes/_globallogic::getcurrentgamemode(); + return self getdstat( "gameHistory", modename, "matchHistory", index, statname ); + } + else + { + return self getdstat( "PlayerStatsByGameType", getgametypename(), "prevScores", index, statname ); + } + } +} + +setrecentstat( isglobal, index, statname, value ) +{ + if ( isDefined( level.nopersistence ) && level.nopersistence ) + { + return; + } + if ( !level.onlinegame ) + { + return; + } + if ( !isstatmodifiable( statname ) ) + { + return; + } + if ( index < 0 || index > 9 ) + { + return; + } + if ( level.wagermatch ) + { + self setdstat( "RecentEarnings", index, statname, value ); + } + else if ( isglobal ) + { + modename = maps/mp/gametypes/_globallogic::getcurrentgamemode(); + self setdstat( "gameHistory", modename, "matchHistory", "" + index, statname, value ); + return; + } + else + { + self setdstat( "PlayerStatsByGameType", getgametypename(), "prevScores", index, statname, value ); + return; + } +} + +addrecentstat( isglobal, index, statname, value ) +{ + if ( isDefined( level.nopersistence ) && level.nopersistence ) + { + return; + } + if ( !level.onlinegame ) + { + return; + } + if ( !isstatmodifiable( statname ) ) + { + return; + } + currstat = getrecentstat( isglobal, index, statname ); + setrecentstat( isglobal, index, statname, currstat + value ); +} + +setmatchhistorystat( statname, value ) +{ + modename = maps/mp/gametypes/_globallogic::getcurrentgamemode(); + historyindex = self getdstat( "gameHistory", modename, "currentMatchHistoryIndex" ); + setrecentstat( 1, historyindex, statname, value ); +} + +addmatchhistorystat( statname, value ) +{ + modename = maps/mp/gametypes/_globallogic::getcurrentgamemode(); + historyindex = self getdstat( "gameHistory", modename, "currentMatchHistoryIndex" ); + addrecentstat( 1, historyindex, statname, value ); +} + +initializematchstats() +{ + if ( isDefined( level.nopersistence ) && level.nopersistence ) + { + return; + } + if ( !level.onlinegame ) + { + return; + } + if ( !level.rankedmatch && !level.wagermatch && !level.leaguematch ) + { + return; + } + self.pers[ "lastHighestScore" ] = self getdstat( "HighestStats", "highest_score" ); + currgametype = maps/mp/gametypes/_persistence::getgametypename(); + self gamehistorystartmatch( getgametypeenumfromname( currgametype, level.hardcoremode ) ); +} + +setafteractionreportstat( statname, value, index ) +{ + if ( self is_bot() ) + { + return; + } +/# + if ( getDvarInt( "scr_writeConfigStrings" ) == 1 || getDvarInt( "scr_hostmigrationtest" ) == 1 ) + { + return; +#/ + } + if ( !level.rankedmatch || level.wagermatch && level.leaguematch ) + { + if ( isDefined( index ) ) + { + self setdstat( "AfterActionReportStats", statname, index, value ); + return; + } + else + { + self setdstat( "AfterActionReportStats", statname, value ); + } + } +} + +codecallback_challengecomplete( rewardxp, maxval, row, tablenumber, challengetype, itemindex, challengeindex ) +{ + self luinotifyevent( &"challenge_complete", 7, challengeindex, itemindex, challengetype, tablenumber, row, maxval, rewardxp ); + self luinotifyeventtospectators( &"challenge_complete", 7, challengeindex, itemindex, challengetype, tablenumber, row, maxval, rewardxp ); +} + +codecallback_gunchallengecomplete( rewardxp, attachmentindex, itemindex, rankid ) +{ + self luinotifyevent( &"gun_level_complete", 4, rankid, itemindex, attachmentindex, rewardxp ); + self luinotifyeventtospectators( &"gun_level_complete", 4, rankid, itemindex, attachmentindex, rewardxp ); +} + +checkcontractexpirations() +{ +} + +incrementcontracttimes( timeinc ) +{ +} + +addcontracttoqueue( index, passed ) +{ +} + +uploadstatssoon() +{ + self notify( "upload_stats_soon" ); + self endon( "upload_stats_soon" ); + self endon( "disconnect" ); + wait 1; + uploadstats( self ); +} + +codecallback_onaddplayerstat( dataname, value ) +{ +} + +codecallback_onaddweaponstat( weapname, dataname, value ) +{ +} + +processcontractsonaddstat( stattype, dataname, value, weapname ) +{ +} diff --git a/patch_mp/maps/mp/gametypes/_pregame.gsc b/patch_mp/maps/mp/gametypes/_pregame.gsc new file mode 100644 index 0000000..2721cfd --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_pregame.gsc @@ -0,0 +1,300 @@ +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/gametypes/_globallogic_ui; +#include maps/mp/gametypes/_hud; +#include maps/mp/gametypes/_globallogic_player; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +main() +{ + level.pregame = 1; +/# + println( "Pregame main() level.pregame = " + level.pregame + "\n" ); +#/ + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 5000 ); + registerroundlimit( 0, 1 ); + registerroundwinlimit( 0, 0 ); + registernumlives( 0, 0 ); + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onendgame = ::onendgame; + level.ontimelimit = ::ontimelimit; + game[ "dialog" ][ "gametype" ] = "pregame_start"; + game[ "dialog" ][ "offense_obj" ] = "generic_boost"; + game[ "dialog" ][ "defense_obj" ] = "generic_boost"; + setscoreboardcolumns( "score", "kills", "deaths", "kdratio", "assists" ); + if ( getDvar( "party_minplayers" ) == "" ) + { + setdvar( "party_minplayers", 4 ); + } + level.pregame_minplayers = getDvarInt( "party_minplayers" ); + setmatchtalkflag( "EveryoneHearsEveryone", 1 ); +} + +onstartgametype() +{ + setclientnamemode( "auto_change" ); + level.spawnmins = ( 1, 1, 1 ); + level.spawnmaxs = ( 1, 1, 1 ); + _a85 = level.teams; + _k85 = getFirstArrayKey( _a85 ); + while ( isDefined( _k85 ) ) + { + team = _a85[ _k85 ]; + setobjectivetext( team, &"OBJECTIVES_PREGAME" ); + setobjectivehinttext( team, &"OBJECTIVES_PREGAME_HINT" ); + if ( level.splitscreen ) + { + setobjectivescoretext( team, &"OBJECTIVES_PREGAME" ); + } + else + { + setobjectivescoretext( team, &"OBJECTIVES_PREGAME_SCORE" ); + } + maps/mp/gametypes/_spawnlogic::addspawnpoints( team, "mp_dm_spawn" ); + _k85 = getNextArrayKey( _a85, _k85 ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.usestartspawns = 0; + level.teambased = 0; + level.overrideteamscore = 1; + level.rankenabled = 0; + level.medalsenabled = 0; + allowed[ 0 ] = "dm"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.killcam = 0; + level.finalkillcam = 0; + level.killstreaksenabled = 0; + startpregame(); +} + +startpregame() +{ + game[ "strings" ][ "waiting_for_players" ] = &"MP_WAITING_FOR_X_PLAYERS"; + game[ "strings" ][ "pregame" ] = &"MP_PREGAME"; + game[ "strings" ][ "pregameover" ] = &"MP_MATCHSTARTING"; + game[ "strings" ][ "pregame_time_limit_reached" ] = &"MP_PREGAME_TIME_LIMIT"; + precachestring( game[ "strings" ][ "waiting_for_players" ] ); + precachestring( game[ "strings" ][ "pregame" ] ); + precachestring( game[ "strings" ][ "pregameover" ] ); + precachestring( game[ "strings" ][ "pregame_time_limit_reached" ] ); + thread pregamemain(); +} + +onspawnplayerunified() +{ + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( self.pers[ "team" ] ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_dm( spawnpoints ); + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "dm" ); + } +} + +onplayerclasschange( response ) +{ + self.pregameclassresponse = response; +} + +endpregame() +{ + level.pregame = 0; + players = level.players; + index = 0; + while ( index < players.size ) + { + player = players[ index ]; + player maps/mp/gametypes/_globallogic_player::freezeplayerforroundend(); + index++; + } + setmatchtalkflag( "EveryoneHearsEveryone", 0 ); + level.pregameplayercount destroyelem(); + level.pregamesubtitle destroyelem(); + level.pregametitle destroyelem(); +} + +getplayersneededcount() +{ + players = level.players; + count = 0; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + team = player.team; + class = player.class; + if ( team != "spectator" ) + { + count++; + } + i++; + } + return int( level.pregame_minplayers - count ); +} + +saveplayerspregameinfo() +{ + players = level.players; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + team = player.team; + class = player.pregameclassresponse; + if ( isDefined( team ) && team != "" ) + { + player setpregameteam( team ); + } + if ( isDefined( class ) && class != "" ) + { + player setpregameclass( class ); + } + i++; + } +} + +pregamemain() +{ + level endon( "game_ended" ); + green = ( 0,6, 0,9, 0,6 ); + red = ( 0,7, 0,3, 0,2 ); + yellow = ( 1, 1, 1 ); + white = ( 1, 1, 1 ); + titlesize = 3; + textsize = 2; + iconsize = 70; + spacing = 30; + font = "objective"; + level.pregametitle = createserverfontstring( font, titlesize ); + level.pregametitle setpoint( "TOP", undefined, 0, 70 ); + level.pregametitle.glowalpha = 1; + level.pregametitle.foreground = 1; + level.pregametitle.hidewheninmenu = 1; + level.pregametitle.archived = 0; + level.pregametitle settext( game[ "strings" ][ "pregame" ] ); + level.pregametitle.color = red; + level.pregamesubtitle = createserverfontstring( font, 2 ); + level.pregamesubtitle setparent( level.pregametitle ); + level.pregamesubtitle setpoint( "TOP", "BOTTOM", 0, 0 ); + level.pregamesubtitle.glowalpha = 1; + level.pregamesubtitle.foreground = 0; + level.pregamesubtitle.hidewheninmenu = 1; + level.pregamesubtitle.archived = 1; + level.pregamesubtitle settext( game[ "strings" ][ "waiting_for_players" ] ); + level.pregamesubtitle.color = green; + level.pregameplayercount = createserverfontstring( font, 2,2 ); + level.pregameplayercount setparent( level.pregametitle ); + level.pregameplayercount setpoint( "TOP", "BOTTOM", -11, 0 ); + level.pregamesubtitle.glowalpha = 1; + level.pregameplayercount.sort = 1001; + level.pregameplayercount.foreground = 0; + level.pregameplayercount.hidewheninmenu = 1; + level.pregameplayercount.archived = 1; + level.pregameplayercount.color = yellow; + level.pregameplayercount maps/mp/gametypes/_hud::fontpulseinit(); + oldcount = -1; + for ( ;; ) + { + wait 1; + count = getplayersneededcount(); + if ( count < 0 ) + { + break; + } + else /# + if ( getDvarInt( "scr_pregame_abort" ) > 0 ) + { + setdvar( "scr_pregame_abort", 0 ); + break; +#/ + } + else + { + if ( oldcount != count ) + { + level.pregameplayercount setvalue( count ); + level.pregameplayercount thread maps/mp/gametypes/_hud::fontpulse( level ); + oldcount = count; + } + } + } + level.pregameplayercount settext( "" ); + level.pregamesubtitle settext( game[ "strings" ][ "pregameover" ] ); + players = level.players; + index = 0; + while ( index < players.size ) + { + player = players[ index ]; + player maps/mp/gametypes/_globallogic_player::freezeplayerforroundend(); + player maps/mp/gametypes/_globallogic_ui::freegameplayhudelems(); + index++; + } + visionsetnaked( "mpIntro", 3 ); + wait 4; + endpregame(); + pregamestartgame(); + saveplayerspregameinfo(); + map_restart( 0 ); +} + +onendgame( winner ) +{ + endpregame(); +} + +ontimelimit() +{ + winner = undefined; + if ( level.teambased ) + { + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbygamestat( "teamScores" ); + maps/mp/gametypes/_globallogic_utils::logteamwinstring( "time limit", winner ); + } + else winner = maps/mp/gametypes/_globallogic_score::gethighestscoringplayer(); + if ( isDefined( winner ) ) + { + logstring( "time limit, win: " + winner.name ); + } + else + { + logstring( "time limit, tie" ); + } + makedvarserverinfo( "ui_text_endreason", game[ "strings" ][ "pregame_time_limit_reached" ] ); + setdvar( "ui_text_endreason", game[ "strings" ][ "time_limit_reached" ] ); + thread maps/mp/gametypes/_globallogic::endgame( winner, game[ "strings" ][ "pregame_time_limit_reached" ] ); +} + +get_pregame_class() +{ + pclass = self getpregameclass(); + if ( isDefined( pclass ) && pclass[ 0 ] != "" ) + { + return pclass; + } + else + { + return "smg_mp,0"; + } +} diff --git a/patch_mp/maps/mp/gametypes/_rank.gsc b/patch_mp/maps/mp/gametypes/_rank.gsc new file mode 100644 index 0000000..97557de --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_rank.gsc @@ -0,0 +1,847 @@ +#include maps/mp/gametypes/_globallogic; +#include maps/mp/gametypes/_hud; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_scoreevents; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + level.scoreinfo = []; + level.xpscale = getDvarFloat( "scr_xpscale" ); + level.codpointsxpscale = getDvarFloat( "scr_codpointsxpscale" ); + level.codpointsmatchscale = getDvarFloat( "scr_codpointsmatchscale" ); + level.codpointschallengescale = getDvarFloat( "scr_codpointsperchallenge" ); + level.rankxpcap = getDvarInt( "scr_rankXpCap" ); + level.codpointscap = getDvarInt( "scr_codPointsCap" ); + level.usingmomentum = 1; + level.usingscorestreaks = getDvarInt( "scr_scorestreaks" ) != 0; + level.scorestreaksmaxstacking = getDvarInt( "scr_scorestreaks_maxstacking" ); + level.maxinventoryscorestreaks = getdvarintdefault( "scr_maxinventory_scorestreaks", 3 ); + if ( isDefined( level.usingscorestreaks ) ) + { + level.usingrampage = !level.usingscorestreaks; + } + level.rampagebonusscale = getDvarFloat( "scr_rampagebonusscale" ); + level.ranktable = []; + precacheshader( "white" ); + precachestring( &"RANK_PLAYER_WAS_PROMOTED_N" ); + precachestring( &"RANK_PLAYER_WAS_PROMOTED" ); + precachestring( &"RANK_PROMOTED" ); + precachestring( &"MP_PLUS" ); + precachestring( &"RANK_ROMANI" ); + precachestring( &"RANK_ROMANII" ); + precachestring( &"MP_SCORE_KILL" ); + if ( !sessionmodeiszombiesgame() ) + { + initscoreinfo(); + } + level.maxrank = int( tablelookup( "mp/rankTable.csv", 0, "maxrank", 1 ) ); + level.maxprestige = int( tablelookup( "mp/rankIconTable.csv", 0, "maxprestige", 1 ) ); + pid = 0; + rid = 0; + pid = 0; + while ( pid <= level.maxprestige ) + { + rid = 0; + while ( rid <= level.maxrank ) + { + precacheshader( tablelookup( "mp/rankIconTable.csv", 0, rid, pid + 1 ) ); + rid++; + } + pid++; + } + rankid = 0; + rankname = tablelookup( "mp/ranktable.csv", 0, rankid, 1 ); +/# + if ( isDefined( rankname ) ) + { + assert( rankname != "" ); + } +#/ + while ( isDefined( rankname ) && rankname != "" ) + { + level.ranktable[ rankid ][ 1 ] = tablelookup( "mp/ranktable.csv", 0, rankid, 1 ); + level.ranktable[ rankid ][ 2 ] = tablelookup( "mp/ranktable.csv", 0, rankid, 2 ); + level.ranktable[ rankid ][ 3 ] = tablelookup( "mp/ranktable.csv", 0, rankid, 3 ); + level.ranktable[ rankid ][ 7 ] = tablelookup( "mp/ranktable.csv", 0, rankid, 7 ); + level.ranktable[ rankid ][ 14 ] = tablelookup( "mp/ranktable.csv", 0, rankid, 14 ); + precachestring( tablelookupistring( "mp/ranktable.csv", 0, rankid, 16 ) ); + rankid++; + rankname = tablelookup( "mp/ranktable.csv", 0, rankid, 1 ); + } + level thread onplayerconnect(); +} + +initscoreinfo() +{ + scoreinfotableid = getscoreeventtableid(); +/# + assert( isDefined( scoreinfotableid ) ); +#/ + if ( !isDefined( scoreinfotableid ) ) + { + return; + } + scorecolumn = getscoreeventcolumn( level.gametype ); + xpcolumn = getxpeventcolumn( level.gametype ); +/# + assert( scorecolumn >= 0 ); +#/ + if ( scorecolumn < 0 ) + { + return; + } +/# + assert( xpcolumn >= 0 ); +#/ + if ( xpcolumn < 0 ) + { + return; + } + row = 1; + while ( row < 512 ) + { + type = tablelookupcolumnforrow( scoreinfotableid, row, 0 ); + if ( type != "" ) + { + labelstring = tablelookupcolumnforrow( scoreinfotableid, row, 1 ); + label = undefined; + if ( labelstring != "" ) + { + label = tablelookupistring( scoreinfotableid, 0, type, 1 ); + } + scorevalue = int( tablelookupcolumnforrow( scoreinfotableid, row, scorecolumn ) ); + registerscoreinfo( type, scorevalue, label ); + if ( maps/mp/_utility::getroundsplayed() == 0 ) + { + xpvalue = float( tablelookupcolumnforrow( scoreinfotableid, row, xpcolumn ) ); + setddlstat = tablelookupcolumnforrow( scoreinfotableid, row, 5 ); + addplayerstat = 0; + if ( setddlstat == "TRUE" ) + { + addplayerstat = 1; + } + ismedal = 0; + istring = tablelookupistring( scoreinfotableid, 0, type, 2 ); + if ( isDefined( istring ) && istring != &"" ) + { + ismedal = 1; + } + demobookmarkpriority = int( tablelookupcolumnforrow( scoreinfotableid, row, 6 ) ); + if ( !isDefined( demobookmarkpriority ) ) + { + demobookmarkpriority = 0; + } + registerxp( type, xpvalue, addplayerstat, ismedal, demobookmarkpriority, row ); + } + allowkillstreakweapons = tablelookupcolumnforrow( scoreinfotableid, row, 4 ); + if ( allowkillstreakweapons == "TRUE" ) + { + level.scoreinfo[ type ][ "allowKillstreakWeapons" ] = 1; + } + } + row++; + } +} + +getrankxpcapped( inrankxp ) +{ + if ( isDefined( level.rankxpcap ) && level.rankxpcap && level.rankxpcap <= inrankxp ) + { + return level.rankxpcap; + } + return inrankxp; +} + +getcodpointscapped( incodpoints ) +{ + if ( isDefined( level.codpointscap ) && level.codpointscap && level.codpointscap <= incodpoints ) + { + return level.codpointscap; + } + return incodpoints; +} + +registerscoreinfo( type, value, label ) +{ + overridedvar = "scr_" + level.gametype + "_score_" + type; + if ( getDvar( overridedvar ) != "" ) + { + value = getDvarInt( overridedvar ); + } + if ( type == "kill" ) + { + multiplier = getgametypesetting( "killEventScoreMultiplier" ); + level.scoreinfo[ type ][ "value" ] = int( ( multiplier + 1 ) * value ); + } + else + { + level.scoreinfo[ type ][ "value" ] = value; + } + if ( isDefined( label ) ) + { + precachestring( label ); + level.scoreinfo[ type ][ "label" ] = label; + } +} + +getscoreinfovalue( type ) +{ + if ( isDefined( level.scoreinfo[ type ] ) ) + { + return level.scoreinfo[ type ][ "value" ]; + } +} + +getscoreinfolabel( type ) +{ + return level.scoreinfo[ type ][ "label" ]; +} + +killstreakweaponsallowedscore( type ) +{ + if ( isDefined( level.scoreinfo[ type ][ "allowKillstreakWeapons" ] ) && level.scoreinfo[ type ][ "allowKillstreakWeapons" ] == 1 ) + { + return 1; + } + else + { + return 0; + } +} + +doesscoreinfocounttowardrampage( type ) +{ + if ( isDefined( level.scoreinfo[ type ][ "rampage" ] ) ) + { + return level.scoreinfo[ type ][ "rampage" ]; + } +} + +getrankinfominxp( rankid ) +{ + return int( level.ranktable[ rankid ][ 2 ] ); +} + +getrankinfoxpamt( rankid ) +{ + return int( level.ranktable[ rankid ][ 3 ] ); +} + +getrankinfomaxxp( rankid ) +{ + return int( level.ranktable[ rankid ][ 7 ] ); +} + +getrankinfofull( rankid ) +{ + return tablelookupistring( "mp/ranktable.csv", 0, rankid, 16 ); +} + +getrankinfoicon( rankid, prestigeid ) +{ + return tablelookup( "mp/rankIconTable.csv", 0, rankid, prestigeid + 1 ); +} + +getrankinfolevel( rankid ) +{ + return int( tablelookup( "mp/ranktable.csv", 0, rankid, 13 ) ); +} + +getrankinfocodpointsearned( rankid ) +{ + return int( tablelookup( "mp/ranktable.csv", 0, rankid, 17 ) ); +} + +shouldkickbyrank() +{ + if ( self ishost() ) + { + return 0; + } + if ( level.rankcap > 0 && self.pers[ "rank" ] > level.rankcap ) + { + return 1; + } + if ( level.rankcap > 0 && level.minprestige == 0 && self.pers[ "plevel" ] > 0 ) + { + return 1; + } + if ( level.minprestige > self.pers[ "plevel" ] ) + { + return 1; + } + return 0; +} + +getcodpointsstat() +{ + codpoints = self getdstat( "playerstatslist", "CODPOINTS", "StatValue" ); + codpointscapped = getcodpointscapped( codpoints ); + if ( codpoints > codpointscapped ) + { + self setcodpointsstat( codpointscapped ); + } + return codpointscapped; +} + +setcodpointsstat( codpoints ) +{ + self setdstat( "PlayerStatsList", "CODPOINTS", "StatValue", getcodpointscapped( codpoints ) ); +} + +getrankxpstat() +{ + rankxp = self getdstat( "playerstatslist", "RANKXP", "StatValue" ); + rankxpcapped = getrankxpcapped( rankxp ); + if ( rankxp > rankxpcapped ) + { + self setdstat( "playerstatslist", "RANKXP", "StatValue", rankxpcapped ); + } + return rankxpcapped; +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player.pers[ "rankxp" ] = player getrankxpstat(); + player.pers[ "codpoints" ] = player getcodpointsstat(); + player.pers[ "currencyspent" ] = player getdstat( "playerstatslist", "currencyspent", "StatValue" ); + rankid = player getrankforxp( player getrankxp() ); + player.pers[ "rank" ] = rankid; + player.pers[ "plevel" ] = player getdstat( "playerstatslist", "PLEVEL", "StatValue" ); + if ( player shouldkickbyrank() ) + { + kick( player getentitynumber() ); + continue; + } + else + { + if ( !isDefined( player.pers[ "participation" ] ) || level.gametype == "twar" && game[ "roundsplayed" ] >= 0 && player.pers[ "participation" ] >= 0 ) + { + player.pers[ "participation" ] = 0; + } + player.rankupdatetotal = 0; + player.cur_ranknum = rankid; +/# + assert( isDefined( player.cur_ranknum ), "rank: " + rankid + " does not have an index, check mp/ranktable.csv" ); +#/ + prestige = player getdstat( "playerstatslist", "plevel", "StatValue" ); + player setrank( rankid, prestige ); + player.pers[ "prestige" ] = prestige; + if ( !isDefined( player.pers[ "summary" ] ) ) + { + player.pers[ "summary" ] = []; + player.pers[ "summary" ][ "xp" ] = 0; + player.pers[ "summary" ][ "score" ] = 0; + player.pers[ "summary" ][ "challenge" ] = 0; + player.pers[ "summary" ][ "match" ] = 0; + player.pers[ "summary" ][ "misc" ] = 0; + player.pers[ "summary" ][ "codpoints" ] = 0; + } + if ( !level.rankedmatch || level.wagermatch && level.leaguematch ) + { + player setdstat( "AfterActionReportStats", "lobbyPopup", "none" ); + } + if ( level.rankedmatch ) + { + player setdstat( "playerstatslist", "rank", "StatValue", rankid ); + player setdstat( "playerstatslist", "minxp", "StatValue", getrankinfominxp( rankid ) ); + player setdstat( "playerstatslist", "maxxp", "StatValue", getrankinfomaxxp( rankid ) ); + player setdstat( "playerstatslist", "lastxp", "StatValue", getrankxpcapped( player.pers[ "rankxp" ] ) ); + } + player.explosivekills[ 0 ] = 0; + player thread onplayerspawned(); + player thread onjoinedteam(); + player thread onjoinedspectators(); + } + } +} + +onjoinedteam() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_team" ); + self thread removerankhud(); + } +} + +onjoinedspectators() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "joined_spectators" ); + self thread removerankhud(); + } +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + if ( !isDefined( self.hud_rankscroreupdate ) ) + { + self.hud_rankscroreupdate = newscorehudelem( self ); + self.hud_rankscroreupdate.horzalign = "center"; + self.hud_rankscroreupdate.vertalign = "middle"; + self.hud_rankscroreupdate.alignx = "center"; + self.hud_rankscroreupdate.aligny = "middle"; + self.hud_rankscroreupdate.x = 0; + if ( self issplitscreen() ) + { + self.hud_rankscroreupdate.y = -15; + } + else + { + self.hud_rankscroreupdate.y = -60; + } + self.hud_rankscroreupdate.font = "default"; + self.hud_rankscroreupdate.fontscale = 2; + self.hud_rankscroreupdate.archived = 0; + self.hud_rankscroreupdate.color = ( 1, 1, 0,5 ); + self.hud_rankscroreupdate.alpha = 0; + self.hud_rankscroreupdate.sort = 50; + self.hud_rankscroreupdate maps/mp/gametypes/_hud::fontpulseinit(); + } + } +} + +inccodpoints( amount ) +{ + if ( !isrankenabled() ) + { + return; + } + if ( !level.rankedmatch ) + { + return; + } + newcodpoints = getcodpointscapped( self.pers[ "codpoints" ] + amount ); + if ( newcodpoints > self.pers[ "codpoints" ] ) + { + self.pers[ "summary" ][ "codpoints" ] += newcodpoints - self.pers[ "codpoints" ]; + } + self.pers[ "codpoints" ] = newcodpoints; + setcodpointsstat( int( newcodpoints ) ); +} + +atleastoneplayeroneachteam() +{ + _a507 = level.teams; + _k507 = getFirstArrayKey( _a507 ); + while ( isDefined( _k507 ) ) + { + team = _a507[ _k507 ]; + if ( !level.playercount[ team ] ) + { + return 0; + } + _k507 = getNextArrayKey( _a507, _k507 ); + } + return 1; +} + +giverankxp( type, value, devadd ) +{ + self endon( "disconnect" ); + if ( sessionmodeiszombiesgame() ) + { + return; + } + if ( level.teambased && !atleastoneplayeroneachteam() && !isDefined( devadd ) ) + { + return; + } + else + { + if ( !level.teambased && maps/mp/gametypes/_globallogic::totalplayercount() < 2 && !isDefined( devadd ) ) + { + return; + } + } + if ( !isrankenabled() ) + { + return; + } + pixbeginevent( "giveRankXP" ); + if ( !isDefined( value ) ) + { + value = getscoreinfovalue( type ); + } + if ( level.rankedmatch ) + { + bbprint( "mpplayerxp", "gametime %d, player %s, type %s, delta %d", getTime(), self.name, type, value ); + } + switch( type ) + { + case "assault": + case "assault_assist": + case "assist": + case "assist_25": + case "assist_50": + case "assist_75": + case "capture": + case "defend": + case "defuse": + case "destroyer": + case "dogassist": + case "dogkill": + case "headshot": + case "helicopterassist": + case "helicopterassist_25": + case "helicopterassist_50": + case "helicopterassist_75": + case "helicopterkill": + case "kill": + case "medal": + case "pickup": + case "plant": + case "rcbombdestroy": + case "return": + case "revive": + case "spyplaneassist": + case "spyplanekill": + value = int( value * level.xpscale ); + break; + default: + if ( level.xpscale == 0 ) + { + value = 0; + } + break; + } + xpincrease = self incrankxp( value ); + if ( level.rankedmatch ) + { + self updaterank(); + } + if ( value != 0 ) + { + self syncxpstat(); + } + if ( isDefined( self.enabletext ) && self.enabletext && !level.hardcoremode ) + { + if ( type == "teamkill" ) + { + self thread updaterankscorehud( 0 - getscoreinfovalue( "kill" ) ); + } + else + { + self thread updaterankscorehud( value ); + } + } + switch( type ) + { + case "assault": + case "assist": + case "assist_25": + case "assist_50": + case "assist_75": + case "capture": + case "defend": + case "headshot": + case "helicopterassist": + case "helicopterassist_25": + case "helicopterassist_50": + case "helicopterassist_75": + case "kill": + case "medal": + case "pickup": + case "return": + case "revive": + case "suicide": + case "teamkill": + self.pers[ "summary" ][ "score" ] += value; + inccodpoints( round_this_number( value * level.codpointsxpscale ) ); + break; + case "loss": + case "tie": + case "win": + self.pers[ "summary" ][ "match" ] += value; + inccodpoints( round_this_number( value * level.codpointsmatchscale ) ); + break; + case "challenge": + self.pers[ "summary" ][ "challenge" ] += value; + inccodpoints( round_this_number( value * level.codpointschallengescale ) ); + break; + default: + self.pers[ "summary" ][ "misc" ] += value; + self.pers[ "summary" ][ "match" ] += value; + inccodpoints( round_this_number( value * level.codpointsmatchscale ) ); + break; + } + self.pers[ "summary" ][ "xp" ] += xpincrease; + pixendevent(); +} + +round_this_number( value ) +{ + value = int( value + 0,5 ); + return value; +} + +updaterank() +{ + newrankid = self getrank(); + if ( newrankid == self.pers[ "rank" ] ) + { + return 0; + } + oldrank = self.pers[ "rank" ]; + rankid = self.pers[ "rank" ]; + self.pers[ "rank" ] = newrankid; + while ( rankid <= newrankid ) + { + self setdstat( "playerstatslist", "rank", "StatValue", rankid ); + self setdstat( "playerstatslist", "minxp", "StatValue", int( level.ranktable[ rankid ][ 2 ] ) ); + self setdstat( "playerstatslist", "maxxp", "StatValue", int( level.ranktable[ rankid ][ 7 ] ) ); + self.setpromotion = 1; + if ( level.rankedmatch && level.gameended && !self issplitscreen() ) + { + self setdstat( "AfterActionReportStats", "lobbyPopup", "promotion" ); + } + if ( rankid != oldrank ) + { + codpointsearnedforrank = getrankinfocodpointsearned( rankid ); + inccodpoints( codpointsearnedforrank ); + if ( !isDefined( self.pers[ "rankcp" ] ) ) + { + self.pers[ "rankcp" ] = 0; + } + self.pers[ "rankcp" ] += codpointsearnedforrank; + } + rankid++; + } + self logstring( "promoted from " + oldrank + " to " + newrankid + " timeplayed: " + self getdstat( "playerstatslist", "time_played_total", "StatValue" ) ); + self setrank( newrankid ); + return 1; +} + +codecallback_rankup( rank, prestige, unlocktokensadded ) +{ + if ( rank > 8 ) + { + self giveachievement( "MP_MISC_1" ); + } + self luinotifyevent( &"rank_up", 3, rank, prestige, unlocktokensadded ); + self luinotifyeventtospectators( &"rank_up", 3, rank, prestige, unlocktokensadded ); +} + +getitemindex( refstring ) +{ + itemindex = int( tablelookup( "mp/statstable.csv", 4, refstring, 0 ) ); +/# + assert( itemindex > 0, "statsTable refstring " + refstring + " has invalid index: " + itemindex ); +#/ + return itemindex; +} + +endgameupdate() +{ + player = self; +} + +updaterankscorehud( amount ) +{ + self endon( "disconnect" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + if ( isDefined( level.usingmomentum ) && level.usingmomentum ) + { + return; + } + if ( amount == 0 ) + { + return; + } + self notify( "update_score" ); + self endon( "update_score" ); + self.rankupdatetotal += amount; + wait 0,05; + if ( isDefined( self.hud_rankscroreupdate ) ) + { + if ( self.rankupdatetotal < 0 ) + { + self.hud_rankscroreupdate.label = &""; + self.hud_rankscroreupdate.color = ( 0,73, 0,19, 0,19 ); + } + else + { + self.hud_rankscroreupdate.label = &"MP_PLUS"; + self.hud_rankscroreupdate.color = ( 1, 1, 0,5 ); + } + self.hud_rankscroreupdate setvalue( self.rankupdatetotal ); + self.hud_rankscroreupdate.alpha = 0,85; + self.hud_rankscroreupdate thread maps/mp/gametypes/_hud::fontpulse( self ); + wait 1; + self.hud_rankscroreupdate fadeovertime( 0,75 ); + self.hud_rankscroreupdate.alpha = 0; + self.rankupdatetotal = 0; + } +} + +updatemomentumhud( amount, reason, reasonvalue ) +{ + self endon( "disconnect" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + if ( amount == 0 ) + { + return; + } + self notify( "update_score" ); + self endon( "update_score" ); + self.rankupdatetotal += amount; + if ( isDefined( self.hud_rankscroreupdate ) ) + { + if ( self.rankupdatetotal < 0 ) + { + self.hud_rankscroreupdate.label = &""; + self.hud_rankscroreupdate.color = ( 0,73, 0,19, 0,19 ); + } + else + { + self.hud_rankscroreupdate.label = &"MP_PLUS"; + self.hud_rankscroreupdate.color = ( 1, 1, 0,5 ); + } + self.hud_rankscroreupdate setvalue( self.rankupdatetotal ); + self.hud_rankscroreupdate.alpha = 0,85; + self.hud_rankscroreupdate thread maps/mp/gametypes/_hud::fontpulse( self ); + if ( isDefined( self.hud_momentumreason ) ) + { + if ( isDefined( reason ) ) + { + if ( isDefined( reasonvalue ) ) + { + self.hud_momentumreason.label = reason; + self.hud_momentumreason setvalue( reasonvalue ); + } + else + { + self.hud_momentumreason.label = reason; + self.hud_momentumreason setvalue( amount ); + } + self.hud_momentumreason.alpha = 0,85; + self.hud_momentumreason thread maps/mp/gametypes/_hud::fontpulse( self ); + } + else + { + self.hud_momentumreason fadeovertime( 0,01 ); + self.hud_momentumreason.alpha = 0; + } + } + wait 1; + self.hud_rankscroreupdate fadeovertime( 0,75 ); + self.hud_rankscroreupdate.alpha = 0; + if ( isDefined( self.hud_momentumreason ) && isDefined( reason ) ) + { + self.hud_momentumreason fadeovertime( 0,75 ); + self.hud_momentumreason.alpha = 0; + } + wait 0,75; + self.rankupdatetotal = 0; + } +} + +removerankhud() +{ + if ( isDefined( self.hud_rankscroreupdate ) ) + { + self.hud_rankscroreupdate.alpha = 0; + } + if ( isDefined( self.hud_momentumreason ) ) + { + self.hud_momentumreason.alpha = 0; + } +} + +getrank() +{ + rankxp = getrankxpcapped( self.pers[ "rankxp" ] ); + rankid = self.pers[ "rank" ]; + if ( rankxp < ( getrankinfominxp( rankid ) + getrankinfoxpamt( rankid ) ) ) + { + return rankid; + } + else + { + return self getrankforxp( rankxp ); + } +} + +getrankforxp( xpval ) +{ + rankid = 0; + rankname = level.ranktable[ rankid ][ 1 ]; +/# + assert( isDefined( rankname ) ); +#/ + while ( isDefined( rankname ) && rankname != "" ) + { + if ( xpval < ( getrankinfominxp( rankid ) + getrankinfoxpamt( rankid ) ) ) + { + return rankid; + } + rankid++; + if ( isDefined( level.ranktable[ rankid ] ) ) + { + rankname = level.ranktable[ rankid ][ 1 ]; + continue; + } + else + { + rankname = undefined; + } + } + rankid--; + + return rankid; +} + +getspm() +{ + ranklevel = self getrank() + 1; + return ( 3 + ( ranklevel * 0,5 ) ) * 10; +} + +getrankxp() +{ + return getrankxpcapped( self.pers[ "rankxp" ] ); +} + +incrankxp( amount ) +{ + if ( !level.rankedmatch ) + { + return 0; + } + xp = self getrankxp(); + newxp = getrankxpcapped( xp + amount ); + if ( self.pers[ "rank" ] == level.maxrank && newxp >= getrankinfomaxxp( level.maxrank ) ) + { + newxp = getrankinfomaxxp( level.maxrank ); + } + xpincrease = getrankxpcapped( newxp ) - self.pers[ "rankxp" ]; + if ( xpincrease < 0 ) + { + xpincrease = 0; + } + self.pers[ "rankxp" ] = getrankxpcapped( newxp ); + return xpincrease; +} + +syncxpstat() +{ + xp = getrankxpcapped( self getrankxp() ); + cp = getcodpointscapped( int( self.pers[ "codpoints" ] ) ); + self setdstat( "playerstatslist", "rankxp", "StatValue", xp ); + self setdstat( "playerstatslist", "codpoints", "StatValue", cp ); +} diff --git a/patch_mp/maps/mp/gametypes/_scoreboard.gsc b/patch_mp/maps/mp/gametypes/_scoreboard.gsc new file mode 100644 index 0000000..9c57984 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_scoreboard.gsc @@ -0,0 +1,25 @@ + +init() +{ + setdvar( "g_ScoresColor_Spectator", ".25 .25 .25" ); + setdvar( "g_ScoresColor_Free", ".76 .78 .10" ); + setdvar( "g_teamColor_MyTeam", ".4 .7 .4" ); + setdvar( "g_teamColor_EnemyTeam", "1 .315 0.35" ); + setdvar( "g_teamColor_MyTeamAlt", ".35 1 1" ); + setdvar( "g_teamColor_EnemyTeamAlt", "1 .5 0" ); + setdvar( "g_teamColor_Squad", ".315 0.35 1" ); + if ( level.createfx_enabled ) + { + return; + } + if ( sessionmodeiszombiesgame() ) + { + setdvar( "g_TeamIcon_Axis", "faction_cia" ); + setdvar( "g_TeamIcon_Allies", "faction_cdc" ); + } + else + { + setdvar( "g_TeamIcon_Axis", game[ "icons" ][ "axis" ] ); + setdvar( "g_TeamIcon_Allies", game[ "icons" ][ "allies" ] ); + } +} diff --git a/patch_mp/maps/mp/gametypes/_serversettings.gsc b/patch_mp/maps/mp/gametypes/_serversettings.gsc new file mode 100644 index 0000000..a747dcc --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_shellshock.gsc b/patch_mp/maps/mp/gametypes/_shellshock.gsc new file mode 100644 index 0000000..c718e80 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_shellshock.gsc @@ -0,0 +1,65 @@ +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precacheshellshock( "frag_grenade_mp" ); + precacheshellshock( "damage_mp" ); + precacherumble( "artillery_rumble" ); + precacherumble( "grenade_rumble" ); +} + +shellshockondamage( cause, damage ) +{ + if ( cause != "MOD_EXPLOSIVE" && cause != "MOD_GRENADE" && cause != "MOD_GRENADE_SPLASH" || cause == "MOD_PROJECTILE" && cause == "MOD_PROJECTILE_SPLASH" ) + { + time = 0; + if ( damage >= 90 ) + { + time = 4; + } + else if ( damage >= 50 ) + { + time = 3; + } + else if ( damage >= 25 ) + { + time = 2; + } + else + { + if ( damage > 10 ) + { + time = 2; + } + } + if ( time ) + { + if ( self mayapplyscreeneffect() ) + { + self shellshock( "frag_grenade_mp", 0.5 ); + } + } + } +} + +endondeath() +{ + self waittill( "death" ); + waittillframeend; + self notify( "end_explode" ); +} + +endontimer( timer ) +{ + self endon( "disconnect" ); + wait timer; + self notify( "end_on_timer" ); +} + +rcbomb_earthquake( position ) +{ + playrumbleonposition( "grenade_rumble", position ); + earthquake( 0.5, 0.5, self.origin, 512 ); +} + diff --git a/patch_mp/maps/mp/gametypes/_spawning.gsc b/patch_mp/maps/mp/gametypes/_spawning.gsc new file mode 100644 index 0000000..ce29a09 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_spawnlogic.gsc b/patch_mp/maps/mp/gametypes/_spawnlogic.gsc new file mode 100644 index 0000000..ba21d0f --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_spectating.gsc b/patch_mp/maps/mp/gametypes/_spectating.gsc new file mode 100644 index 0000000..31ce9f4 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_tweakables.gsc b/patch_mp/maps/mp/gametypes/_tweakables.gsc new file mode 100644 index 0000000..4b85e4a --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_wager.gsc b/patch_mp/maps/mp/gametypes/_wager.gsc new file mode 100644 index 0000000..e244cee --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_wager.gsc @@ -0,0 +1,988 @@ +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes/_class; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/teams/_teams; +#include maps/mp/gametypes/_globallogic; +#include maps/mp/gametypes/_persistence; +#include maps/mp/gametypes/_rank; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/gametypes/_globallogic_score; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + precachestring( &"MP_HEADS_UP" ); + precachestring( &"MP_U2_ONLINE" ); + precachestring( &"MP_BONUS_ACQUIRED" ); + if ( gamemodeismode( level.gamemode_wager_match ) && !ispregame() ) + { + level.wagermatch = 1; + if ( !isDefined( game[ "wager_pot" ] ) ) + { + game[ "wager_pot" ] = 0; + game[ "wager_initial_pot" ] = 0; + } + game[ "dialog" ][ "wm_u2_online" ] = "boost_gen_02"; + game[ "dialog" ][ "wm_in_the_money" ] = "boost_gen_06"; + game[ "dialog" ][ "wm_oot_money" ] = "boost_gen_07"; + level.poweruplist = []; + level thread onplayerconnect(); + level thread helpgameend(); + } + else + { + level.wagermatch = 0; + } + level.takelivesondeath = 1; +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread ondisconnect(); + player thread initwagerplayer(); + } +} + +initwagerplayer() +{ + self endon( "disconnect" ); + self waittill( "spawned_player" ); + if ( !isDefined( self.pers[ "wager" ] ) ) + { + self.pers[ "wager" ] = 1; + self.pers[ "wager_sideBetWinnings" ] = 0; + self.pers[ "wager_sideBetLosses" ] = 0; + } + if ( isDefined( level.inthemoneyonradar ) || level.inthemoneyonradar && isDefined( level.firstplaceonradar ) && level.firstplaceonradar ) + { + self.pers[ "hasRadar" ] = 1; + self.hasspyplane = 1; + } + else + { + self.pers[ "hasRadar" ] = 0; + self.hasspyplane = 0; + } + self thread deductplayerante(); +} + +ondisconnect() +{ + level endon( "game_ended" ); + self endon( "player_eliminated" ); + self waittill( "disconnect" ); + level notify( "player_eliminated" ); +} + +deductplayerante() +{ + if ( isDefined( self.pers[ "hasPaidWagerAnte" ] ) ) + { + return; + } + waittillframeend; + codpoints = self maps/mp/gametypes/_rank::getcodpointsstat(); + wagerbet = getDvarInt( "scr_wagerBet" ); + if ( wagerbet > codpoints ) + { + wagerbet = codpoints; + } + codpoints -= wagerbet; + self maps/mp/gametypes/_rank::setcodpointsstat( codpoints ); + if ( !self islocaltohost() ) + { + self incrementescrowforplayer( wagerbet ); + } + game[ "wager_pot" ] += wagerbet; + game[ "wager_initial_pot" ] += wagerbet; + self.pers[ "hasPaidWagerAnte" ] = 1; + self addplayerstat( "LIFETIME_BUYIN", wagerbet ); + self addrecentearningstostat( 0 - wagerbet ); + if ( isDefined( level.onwagerplayerante ) ) + { + [[ level.onwagerplayerante ]]( self, wagerbet ); + } + self thread maps/mp/gametypes/_persistence::uploadstatssoon(); +} + +incrementescrowforplayer( amount ) +{ + if ( !isDefined( self ) || !isplayer( self ) ) + { + return; + } + if ( !isDefined( game[ "escrows" ] ) ) + { + game[ "escrows" ] = []; + } + playerxuid = self getxuid(); + if ( !isDefined( playerxuid ) ) + { + return; + } + escrowstruct = spawnstruct(); + escrowstruct.xuid = playerxuid; + escrowstruct.amount = amount; + game[ "escrows" ][ game[ "escrows" ].size ] = escrowstruct; +} + +clearescrows() +{ + if ( !isDefined( game[ "escrows" ] ) ) + { + return; + } + escrows = game[ "escrows" ]; + numescrows = escrows.size; + i = 0; + while ( i < numescrows ) + { + escrowstruct = escrows[ i ]; + i++; + } + game[ "escrows" ] = []; +} + +addrecentearningstostat( recentearnings ) +{ + currearnings = self maps/mp/gametypes/_persistence::getrecentstat( 1, 0, "score" ); + self maps/mp/gametypes/_persistence::setrecentstat( 1, 0, "score", currearnings + recentearnings ); +} + +prematchperiod() +{ + if ( !level.wagermatch ) + { + return; + } +} + +finalizewagerround() +{ + if ( level.wagermatch == 0 ) + { + return; + } + determinewagerwinnings(); + if ( isDefined( level.onwagerfinalizeround ) ) + { + [[ level.onwagerfinalizeround ]](); + } +} + +determinewagerwinnings() +{ + if ( isDefined( level.dontcalcwagerwinnings ) ) + { + shouldcalculatewinnings = !level.dontcalcwagerwinnings; + } + if ( !shouldcalculatewinnings ) + { + return; + } + if ( !level.teambased ) + { + calculatefreeforallpayouts(); + } + else + { + calculateteampayouts(); + } +} + +calculatefreeforallpayouts() +{ + playerrankings = level.placement[ "all" ]; + payoutpercentages = array( 0,5, 0,3, 0,2 ); + if ( playerrankings.size == 2 ) + { + payoutpercentages = array( 0,7, 0,3 ); + } + else + { + if ( playerrankings.size == 1 ) + { + payoutpercentages = array( 1 ); + } + } + setwagerwinningsonplayers( level.players, 0 ); + if ( isDefined( level.hostforcedend ) && level.hostforcedend ) + { + wagerbet = getDvarInt( "scr_wagerBet" ); + i = 0; + while ( i < playerrankings.size ) + { + if ( !playerrankings[ i ] islocaltohost() ) + { + playerrankings[ i ].wagerwinnings = wagerbet; + } + i++; + } + } + else if ( level.players.size == 1 ) + { + return; + } + else + { + currentpayoutpercentage = 0; + cumulativepayoutpercentage = payoutpercentages[ 0 ]; + playergroup = []; + playergroup[ playergroup.size ] = playerrankings[ 0 ]; + i = 1; + while ( i < playerrankings.size ) + { + if ( playerrankings[ i ].pers[ "score" ] < playergroup[ 0 ].pers[ "score" ] ) + { + setwagerwinningsonplayers( playergroup, int( ( game[ "wager_pot" ] * cumulativepayoutpercentage ) / playergroup.size ) ); + playergroup = []; + cumulativepayoutpercentage = 0; + } + playergroup[ playergroup.size ] = playerrankings[ i ]; + currentpayoutpercentage++; + if ( isDefined( payoutpercentages[ currentpayoutpercentage ] ) ) + { + cumulativepayoutpercentage += payoutpercentages[ currentpayoutpercentage ]; + } + i++; + } + setwagerwinningsonplayers( playergroup, int( ( game[ "wager_pot" ] * cumulativepayoutpercentage ) / playergroup.size ) ); + } +} + +calculateplacesbasedonscore() +{ + level.playerplaces = array( [], [], [] ); + playerrankings = level.placement[ "all" ]; + placementscores = array( playerrankings[ 0 ].pers[ "score" ], -1, -1 ); + currentplace = 0; + index = 0; + while ( index < playerrankings.size && currentplace < placementscores.size ) + { + player = playerrankings[ index ]; + if ( player.pers[ "score" ] < placementscores[ currentplace ] ) + { + currentplace++; + if ( currentplace >= level.playerplaces.size ) + { + return; + } + else + { + placementscores[ currentplace ] = player.pers[ "score" ]; + } + level.playerplaces[ currentplace ][ level.playerplaces[ currentplace ].size ] = player; + index++; + } + } +} + +calculateteampayouts() +{ + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbygamestat( "teamScores" ); + if ( winner == "tie" ) + { + calculatefreeforallpayouts(); + return; + } + playersonwinningteam = []; + index = 0; + while ( index < level.players.size ) + { + player = level.players[ index ]; + player.wagerwinnings = 0; + if ( player.pers[ "team" ] == winner ) + { + playersonwinningteam[ playersonwinningteam.size ] = player; + } + index++; + } + if ( playersonwinningteam.size == 0 ) + { + setwagerwinningsonplayers( level.players, getDvarInt( "scr_wagerBet" ) ); + return; + } + winningssplit = int( game[ "wager_pot" ] / playersonwinningteam.size ); + setwagerwinningsonplayers( playersonwinningteam, winningssplit ); +} + +setwagerwinningsonplayers( players, amount ) +{ + index = 0; + while ( index < players.size ) + { + players[ index ].wagerwinnings = amount; + index++; + } +} + +finalizewagergame() +{ + level.wagergamefinalized = 1; + if ( level.wagermatch == 0 ) + { + return; + } + determinewagerwinnings(); + determinetopearners(); + players = level.players; + wait 0,5; + playerrankings = level.wagertopearners; + index = 0; + while ( index < players.size ) + { + player = players[ index ]; + if ( isDefined( player.pers[ "wager_sideBetWinnings" ] ) ) + { + payoutwagerwinnings( player, player.wagerwinnings + player.pers[ "wager_sideBetWinnings" ] ); + } + else + { + payoutwagerwinnings( player, player.wagerwinnings ); + } + if ( player.wagerwinnings > 0 ) + { + maps/mp/gametypes/_globallogic_score::updatewinstats( player ); + } + index++; + } + clearescrows(); +} + +payoutwagerwinnings( player, winnings ) +{ + if ( winnings == 0 ) + { + return; + } + codpoints = player maps/mp/gametypes/_rank::getcodpointsstat(); + player maps/mp/gametypes/_rank::setcodpointsstat( codpoints + winnings ); + player addplayerstat( "LIFETIME_EARNINGS", winnings ); + player addrecentearningstostat( winnings ); +} + +determinetopearners() +{ + topwinnings = array( -1, -1, -1 ); + level.wagertopearners = []; + index = 0; + while ( index < level.players.size ) + { + player = level.players[ index ]; + if ( !isDefined( player.wagerwinnings ) ) + { + player.wagerwinnings = 0; + } + if ( player.wagerwinnings > topwinnings[ 0 ] ) + { + topwinnings[ 2 ] = topwinnings[ 1 ]; + topwinnings[ 1 ] = topwinnings[ 0 ]; + topwinnings[ 0 ] = player.wagerwinnings; + level.wagertopearners[ 2 ] = level.wagertopearners[ 1 ]; + level.wagertopearners[ 1 ] = level.wagertopearners[ 0 ]; + level.wagertopearners[ 0 ] = player; + index++; + continue; + } + else if ( player.wagerwinnings > topwinnings[ 1 ] ) + { + topwinnings[ 2 ] = topwinnings[ 1 ]; + topwinnings[ 1 ] = player.wagerwinnings; + level.wagertopearners[ 2 ] = level.wagertopearners[ 1 ]; + level.wagertopearners[ 1 ] = player; + index++; + continue; + } + else + { + if ( player.wagerwinnings > topwinnings[ 2 ] ) + { + topwinnings[ 2 ] = player.wagerwinnings; + level.wagertopearners[ 2 ] = player; + } + } + index++; + } +} + +postroundsidebet() +{ + if ( isDefined( level.sidebet ) && level.sidebet ) + { + level notify( "side_bet_begin" ); + level waittill( "side_bet_end" ); + } +} + +sidebettimer() +{ + level endon( "side_bet_end" ); + secondstowait = ( level.sidebetendtime - getTime() ) / 1000; + if ( secondstowait < 0 ) + { + secondstowait = 0; + } + wait secondstowait; + playerindex = 0; + while ( playerindex < level.players.size ) + { + if ( isDefined( level.players[ playerindex ] ) ) + { + level.players[ playerindex ] closemenu(); + } + playerindex++; + } + level notify( "side_bet_end" ); +} + +sidebetallbetsplaced() +{ + secondsleft = ( level.sidebetendtime - getTime() ) / 1000; + if ( secondsleft <= 3 ) + { + return; + } + level.sidebetendtime = getTime() + 3000; + wait 3; + playerindex = 0; + while ( playerindex < level.players.size ) + { + if ( isDefined( level.players[ playerindex ] ) ) + { + level.players[ playerindex ] closemenu(); + } + playerindex++; + } + level notify( "side_bet_end" ); +} + +setupblankrandomplayer( takeweapons, chooserandombody, weapon ) +{ + if ( !isDefined( chooserandombody ) || chooserandombody ) + { + if ( !isDefined( self.pers[ "wagerBodyAssigned" ] ) ) + { + self assignrandombody(); + self.pers[ "wagerBodyAssigned" ] = 1; + } + self maps/mp/teams/_teams::set_player_model( self.team, weapon ); + } + self clearperks(); + self.killstreak = []; + self.pers[ "killstreaks" ] = []; + self.pers[ "killstreak_has_been_used" ] = []; + self.pers[ "killstreak_unique_id" ] = []; + if ( !isDefined( takeweapons ) || takeweapons ) + { + self takeallweapons(); + } + if ( isDefined( self.pers[ "hasRadar" ] ) && self.pers[ "hasRadar" ] ) + { + self.hasspyplane = 1; + } + while ( isDefined( self.powerups ) && isDefined( self.powerups.size ) ) + { + i = 0; + while ( i < self.powerups.size ) + { + self applypowerup( self.powerups[ i ] ); + i++; + } + } + self setradarvisibility(); +} + +assignrandombody() +{ +} + +queuewagerpopup( message, points, submessage, announcement ) +{ + self endon( "disconnect" ); + size = self.wagernotifyqueue.size; + self.wagernotifyqueue[ size ] = spawnstruct(); + self.wagernotifyqueue[ size ].message = message; + self.wagernotifyqueue[ size ].points = points; + self.wagernotifyqueue[ size ].submessage = submessage; + self.wagernotifyqueue[ size ].announcement = announcement; + self notify( "received award" ); +} + +helpgameend() +{ + level endon( "game_ended" ); + for ( ;; ) + { + level waittill( "player_eliminated" ); + if ( !isDefined( level.numlives ) || !level.numlives ) + { + continue; + } + else + { + wait 0,05; + players = level.players; + playersleft = 0; + i = 0; + while ( i < players.size ) + { + if ( isDefined( players[ i ].pers[ "lives" ] ) && players[ i ].pers[ "lives" ] > 0 ) + { + playersleft++; + } + i++; + } + while ( playersleft == 2 ) + { + i = 0; + while ( i < players.size ) + { + players[ i ] queuewagerpopup( &"MP_HEADS_UP", 0, &"MP_U2_ONLINE", "wm_u2_online" ); + players[ i ].pers[ "hasRadar" ] = 1; + players[ i ].hasspyplane = 1; + level.activeuavs[ players[ i ] getentitynumber() ]++; + i++; + } + } + } + } +} + +setradarvisibility() +{ + prevscoreplace = self.prevscoreplace; + if ( !isDefined( prevscoreplace ) ) + { + prevscoreplace = 1; + } + if ( isDefined( level.inthemoneyonradar ) && level.inthemoneyonradar ) + { + if ( prevscoreplace <= 3 && isDefined( self.score ) && self.score > 0 ) + { + self unsetperk( "specialty_gpsjammer" ); + } + else + { + self setperk( "specialty_gpsjammer" ); + } + } + else + { + if ( isDefined( level.firstplaceonradar ) && level.firstplaceonradar ) + { + if ( prevscoreplace == 1 && isDefined( self.score ) && self.score > 0 ) + { + self unsetperk( "specialty_gpsjammer" ); + return; + } + else + { + self setperk( "specialty_gpsjammer" ); + } + } + } +} + +playerscored() +{ + self notify( "wager_player_scored" ); + self endon( "wager_player_scored" ); + wait 0,05; + maps/mp/gametypes/_globallogic::updateplacement(); + i = 0; + while ( i < level.placement[ "all" ].size ) + { + prevscoreplace = level.placement[ "all" ][ i ].prevscoreplace; + if ( !isDefined( prevscoreplace ) ) + { + prevscoreplace = 1; + } + currentscoreplace = i + 1; + j = i - 1; + while ( j >= 0 ) + { + if ( level.placement[ "all" ][ i ].score == level.placement[ "all" ][ j ].score ) + { + currentscoreplace--; + + } + j--; + + } + wasinthemoney = prevscoreplace <= 3; + isinthemoney = currentscoreplace <= 3; + if ( !wasinthemoney && isinthemoney ) + { + level.placement[ "all" ][ i ] wagerannouncer( "wm_in_the_money" ); + } + else + { + if ( wasinthemoney && !isinthemoney ) + { + level.placement[ "all" ][ i ] wagerannouncer( "wm_oot_money" ); + } + } + level.placement[ "all" ][ i ].prevscoreplace = currentscoreplace; + level.placement[ "all" ][ i ] setradarvisibility(); + i++; + } +} + +wagerannouncer( dialog, group ) +{ + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( dialog, group ); +} + +createpowerup( name, type, displayname, iconmaterial ) +{ + powerup = spawnstruct(); + powerup.name = []; + powerup.name[ 0 ] = name; + powerup.type = type; + powerup.displayname = displayname; + powerup.iconmaterial = iconmaterial; + return powerup; +} + +addpowerup( name, type, displayname, iconmaterial ) +{ + if ( !isDefined( level.poweruplist ) ) + { + level.poweruplist = []; + } + i = 0; + while ( i < level.poweruplist.size ) + { + if ( level.poweruplist[ i ].displayname == displayname ) + { + level.poweruplist[ i ].name[ level.poweruplist[ i ].name.size ] = name; + return; + } + i++; + } + powerup = createpowerup( name, type, displayname, iconmaterial ); + level.poweruplist[ level.poweruplist.size ] = powerup; +} + +copypowerup( powerup ) +{ + return createpowerup( powerup.name[ 0 ], powerup.type, powerup.displayname, powerup.iconmaterial ); +} + +applypowerup( powerup ) +{ + switch( powerup.type ) + { + case "primary": + self giveweapon( powerup.name[ 0 ] ); + self switchtoweapon( powerup.name[ 0 ] ); + break; + case "secondary": + self giveweapon( powerup.name[ 0 ] ); + break; + case "equipment": + self giveweapon( powerup.name[ 0 ] ); + self maps/mp/gametypes/_class::setweaponammooverall( powerup.name[ 0 ], 1 ); + self setactionslot( 1, "weapon", powerup.name[ 0 ] ); + break; + case "primary_grenade": + self setoffhandprimaryclass( powerup.name[ 0 ] ); + self giveweapon( powerup.name[ 0 ] ); + self setweaponammoclip( powerup.name[ 0 ], 2 ); + break; + case "secondary_grenade": + self setoffhandsecondaryclass( powerup.name[ 0 ] ); + self giveweapon( powerup.name[ 0 ] ); + self setweaponammoclip( powerup.name[ 0 ], 2 ); + break; + case "perk": + i = 0; + while ( i < powerup.name.size ) + { + self setperk( powerup.name[ i ] ); + i++; + } + case "killstreak": + self maps/mp/killstreaks/_killstreaks::givekillstreak( powerup.name[ 0 ] ); + break; + case "score_multiplier": + self.scoremultiplier = powerup.name[ 0 ]; + break; + } + } +} + +givepowerup( powerup, doanimation ) +{ + if ( !isDefined( self.powerups ) ) + { + self.powerups = []; + } + powerupindex = self.powerups.size; + self.powerups[ powerupindex ] = copypowerup( powerup ); + i = 0; + while ( i < powerup.name.size ) + { + self.powerups[ powerupindex ].name[ self.powerups[ powerupindex ].name.size ] = powerup.name[ i ]; + i++; + } + self applypowerup( self.powerups[ powerupindex ] ); + self thread showpowerupmessage( powerupindex, doanimation ); +} + +pulsepowerupicon( powerupindex ) +{ + if ( isDefined( self ) && isDefined( self.powerups ) || !isDefined( self.powerups[ powerupindex ] ) && !isDefined( self.powerups[ powerupindex ].hud_elem_icon ) ) + { + return; + } + self endon( "disconnect" ); + self endon( "delete" ); + self endon( "clearing_powerups" ); + pulsepercent = 1,5; + pulsetime = 0,5; + hud_elem = self.powerups[ powerupindex ].hud_elem_icon; + if ( isDefined( hud_elem.animating ) && hud_elem.animating ) + { + return; + } + origx = hud_elem.x; + origy = hud_elem.y; + origwidth = hud_elem.width; + origheight = hud_elem.height; + bigwidth = origwidth * pulsepercent; + bigheight = origheight * pulsepercent; + xoffset = ( bigwidth - origwidth ) / 2; + yoffset = ( bigheight - origheight ) / 2; + hud_elem scaleovertime( 0,05, int( bigwidth ), int( bigheight ) ); + hud_elem moveovertime( 0,05 ); + hud_elem.x = origx - xoffset; + hud_elem.y = origy - yoffset; + wait 0,05; + hud_elem scaleovertime( pulsetime, origwidth, origheight ); + hud_elem moveovertime( pulsetime ); + hud_elem.x = origx; + hud_elem.y = origy; +} + +showpowerupmessage( powerupindex, doanimation ) +{ + self endon( "disconnect" ); + self endon( "delete" ); + self endon( "clearing_powerups" ); + if ( !isDefined( doanimation ) ) + { + doanimation = 1; + } + wasinprematch = level.inprematchperiod; + powerupstarty = 320; + powerupspacing = 40; + if ( self issplitscreen() ) + { + powerupstarty = 120; + powerupspacing = 35; + } + if ( isDefined( self.powerups[ powerupindex ].hud_elem ) ) + { + self.powerups[ powerupindex ].hud_elem destroy(); + } + self.powerups[ powerupindex ].hud_elem = newclienthudelem( self ); + self.powerups[ powerupindex ].hud_elem.fontscale = 1,5; + self.powerups[ powerupindex ].hud_elem.x = -125; + self.powerups[ powerupindex ].hud_elem.y = powerupstarty - ( powerupspacing * powerupindex ); + self.powerups[ powerupindex ].hud_elem.alignx = "left"; + self.powerups[ powerupindex ].hud_elem.aligny = "middle"; + self.powerups[ powerupindex ].hud_elem.horzalign = "user_right"; + self.powerups[ powerupindex ].hud_elem.vertalign = "user_top"; + self.powerups[ powerupindex ].hud_elem.color = ( 1, 1, 1 ); + self.powerups[ powerupindex ].hud_elem.foreground = 1; + self.powerups[ powerupindex ].hud_elem.hidewhendead = 0; + self.powerups[ powerupindex ].hud_elem.hidewheninmenu = 1; + self.powerups[ powerupindex ].hud_elem.hidewheninkillcam = 1; + self.powerups[ powerupindex ].hud_elem.archived = 0; + self.powerups[ powerupindex ].hud_elem.alpha = 0; + self.powerups[ powerupindex ].hud_elem settext( self.powerups[ powerupindex ].displayname ); + bigiconsize = 40; + iconsize = 32; + if ( isDefined( self.powerups[ powerupindex ].hud_elem_icon ) ) + { + self.powerups[ powerupindex ].hud_elem_icon destroy(); + } + if ( doanimation ) + { + self.powerups[ powerupindex ].hud_elem_icon = self createicon( self.powerups[ powerupindex ].iconmaterial, bigiconsize, bigiconsize ); + self.powerups[ powerupindex ].hud_elem_icon.animating = 1; + } + else + { + self.powerups[ powerupindex ].hud_elem_icon = self createicon( self.powerups[ powerupindex ].iconmaterial, iconsize, iconsize ); + } + self.powerups[ powerupindex ].hud_elem_icon.x = ( ( self.powerups[ powerupindex ].hud_elem.x - 5 ) - ( iconsize / 2 ) ) - ( bigiconsize / 2 ); + self.powerups[ powerupindex ].hud_elem_icon.y = ( powerupstarty - ( powerupspacing * powerupindex ) ) - ( bigiconsize / 2 ); + self.powerups[ powerupindex ].hud_elem_icon.horzalign = "user_right"; + self.powerups[ powerupindex ].hud_elem_icon.vertalign = "user_top"; + self.powerups[ powerupindex ].hud_elem_icon.color = ( 1, 1, 1 ); + self.powerups[ powerupindex ].hud_elem_icon.foreground = 1; + self.powerups[ powerupindex ].hud_elem_icon.hidewhendead = 0; + self.powerups[ powerupindex ].hud_elem_icon.hidewheninmenu = 1; + self.powerups[ powerupindex ].hud_elem_icon.hidewheninkillcam = 1; + self.powerups[ powerupindex ].hud_elem_icon.archived = 0; + self.powerups[ powerupindex ].hud_elem_icon.alpha = 1; + if ( !wasinprematch && doanimation ) + { + self thread queuewagerpopup( self.powerups[ powerupindex ].displayname, 0, &"MP_BONUS_ACQUIRED" ); + } + pulsetime = 0,5; + if ( doanimation ) + { + self.powerups[ powerupindex ].hud_elem fadeovertime( pulsetime ); + self.powerups[ powerupindex ].hud_elem_icon scaleovertime( pulsetime, iconsize, iconsize ); + self.powerups[ powerupindex ].hud_elem_icon.width = iconsize; + self.powerups[ powerupindex ].hud_elem_icon.height = iconsize; + self.powerups[ powerupindex ].hud_elem_icon moveovertime( pulsetime ); + } + self.powerups[ powerupindex ].hud_elem.alpha = 1; + self.powerups[ powerupindex ].hud_elem_icon.x = ( self.powerups[ powerupindex ].hud_elem.x - 5 ) - iconsize; + self.powerups[ powerupindex ].hud_elem_icon.y = ( powerupstarty - ( powerupspacing * powerupindex ) ) - ( iconsize / 2 ); + if ( doanimation ) + { + wait pulsetime; + } + if ( level.inprematchperiod ) + { + level waittill( "prematch_over" ); + } + else + { + if ( doanimation ) + { + wait pulsetime; + } + } + if ( wasinprematch && doanimation ) + { + self thread queuewagerpopup( self.powerups[ powerupindex ].displayname, 0, &"MP_BONUS_ACQUIRED" ); + } + wait 1,5; + i = 0; + while ( i <= powerupindex ) + { + self.powerups[ i ].hud_elem fadeovertime( 0,25 ); + self.powerups[ i ].hud_elem.alpha = 0; + i++; + } + wait 0,25; + i = 0; + while ( i <= powerupindex ) + { + self.powerups[ i ].hud_elem_icon moveovertime( 0,25 ); + self.powerups[ i ].hud_elem_icon.x = 0 - iconsize; + self.powerups[ i ].hud_elem_icon.horzalign = "user_right"; + i++; + } + self.powerups[ powerupindex ].hud_elem_icon.animating = 0; +} + +clearpowerups() +{ + self notify( "clearing_powerups" ); + while ( isDefined( self.powerups ) && isDefined( self.powerups.size ) ) + { + i = 0; + while ( i < self.powerups.size ) + { + if ( isDefined( self.powerups[ i ].hud_elem ) ) + { + self.powerups[ i ].hud_elem destroy(); + } + if ( isDefined( self.powerups[ i ].hud_elem_icon ) ) + { + self.powerups[ i ].hud_elem_icon destroy(); + } + i++; + } + } + self.powerups = []; +} + +trackwagerweaponusage( name, incvalue, statname ) +{ + if ( !isDefined( self.wagerweaponusage ) ) + { + self.wagerweaponusage = []; + } + if ( !isDefined( self.wagerweaponusage[ name ] ) ) + { + self.wagerweaponusage[ name ] = []; + } + if ( !isDefined( self.wagerweaponusage[ name ][ statname ] ) ) + { + self.wagerweaponusage[ name ][ statname ] = 0; + } + self.wagerweaponusage[ name ][ statname ] += incvalue; +} + +gethighestwagerweaponusage( statname ) +{ + if ( !isDefined( self.wagerweaponusage ) ) + { + return undefined; + } + bestweapon = undefined; + highestvalue = 0; + wagerweaponsused = getarraykeys( self.wagerweaponusage ); + i = 0; + while ( i < wagerweaponsused.size ) + { + weaponstats = self.wagerweaponusage[ wagerweaponsused[ i ] ]; + if ( !isDefined( weaponstats[ statname ] ) || !getbaseweaponitemindex( wagerweaponsused[ i ] ) ) + { + i++; + continue; + } + else if ( !isDefined( bestweapon ) || weaponstats[ statname ] > highestvalue ) + { + bestweapon = wagerweaponsused[ i ]; + highestvalue = weaponstats[ statname ]; + } + i++; + } + return bestweapon; +} + +setwagerafteractionreportstats() +{ + topweapon = self gethighestwagerweaponusage( "kills" ); + topkills = 0; + if ( isDefined( topweapon ) ) + { + topkills = self.wagerweaponusage[ topweapon ][ "kills" ]; + } + else + { + topweapon = self gethighestwagerweaponusage( "timeUsed" ); + } + if ( !isDefined( topweapon ) ) + { + topweapon = ""; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "topWeaponItemIndex", getbaseweaponitemindex( topweapon ) ); + self maps/mp/gametypes/_persistence::setafteractionreportstat( "topWeaponKills", topkills ); + if ( isDefined( level.onwagerawards ) ) + { + self [[ level.onwagerawards ]](); + } + else + { + i = 0; + while ( i < 3 ) + { + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", 0, i ); + i++; + } + } +} diff --git a/patch_mp/maps/mp/gametypes/_weapon_utils.gsc b/patch_mp/maps/mp/gametypes/_weapon_utils.gsc new file mode 100644 index 0000000..7359766 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_weaponobjects.gsc b/patch_mp/maps/mp/gametypes/_weaponobjects.gsc new file mode 100644 index 0000000..8953fc5 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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_mp/maps/mp/gametypes/_weapons.gsc b/patch_mp/maps/mp/gametypes/_weapons.gsc new file mode 100644 index 0000000..c70cd9c --- /dev/null +++ b/patch_mp/maps/mp/gametypes/_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; +} diff --git a/patch_mp/maps/mp/gametypes/conf.gsc b/patch_mp/maps/mp/gametypes/conf.gsc new file mode 100644 index 0000000..b02fd44 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/conf.gsc @@ -0,0 +1,521 @@ +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_objpoints; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_spawnlogic; +#include common_scripts/utility; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +main() +{ + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 50000 ); + registerroundlimit( 0, 10 ); + registerroundswitch( 0, 9 ); + registerroundwinlimit( 0, 10 ); + registernumlives( 0, 100 ); + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + level.scoreroundbased = 1; + level.teambased = 1; + level.onprecachegametype = ::onprecachegametype; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onroundendgame = ::onroundendgame; + level.onplayerkilled = ::onplayerkilled; + level.onroundswitch = ::onroundswitch; + level.overrideteamscore = 1; + level.teamscoreperkill = getgametypesetting( "teamScorePerKill" ); + level.teamscoreperkillconfirmed = getgametypesetting( "teamScorePerKillConfirmed" ); + level.teamscoreperkilldenied = getgametypesetting( "teamScorePerKillDenied" ); + level.antiboostdistance = getgametypesetting( "antiBoostDistance" ); + game[ "dialog" ][ "gametype" ] = "kc_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "kc_start"; + game[ "dialog" ][ "offense_obj" ] = "generic_boost"; + game[ "dialog" ][ "defense_obj" ] = "generic_boost"; + game[ "dialog" ][ "kc_deny" ] = "kc_deny"; + game[ "dialog" ][ "kc_start" ] = "kc_start"; + game[ "dialog" ][ "kc_denied" ] = "mpl_kc_killdeny"; + level.conf_fx[ "vanish" ] = loadfx( "maps/mp_maps/fx_mp_kill_confirmed_vanish" ); + if ( !sessionmodeissystemlink() && !sessionmodeisonlinegame() && issplitscreen() ) + { + setscoreboardcolumns( "score", "kills", "killsconfirmed", "killsdenied", "deaths" ); + } + else + { + setscoreboardcolumns( "score", "kills", "deaths", "killsconfirmed", "killsdenied" ); + } +} + +onprecachegametype() +{ + precachemodel( "p6_dogtags" ); + precachemodel( "p6_dogtags_friend" ); + precacheshader( "waypoint_dogtags" ); + precachestring( &"MP_KILL_DENIED" ); +} + +onstartgametype() +{ + setclientnamemode( "auto_change" ); + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + if ( game[ "switchedsides" ] ) + { + oldattackers = game[ "attackers" ]; + olddefenders = game[ "defenders" ]; + game[ "attackers" ] = olddefenders; + game[ "defenders" ] = oldattackers; + } + allowed[ 0 ] = level.gametype; + maps/mp/gametypes/_gameobjects::main( allowed ); + level.spawnmins = ( 0, 0, 1 ); + level.spawnmaxs = ( 0, 0, 1 ); + _a109 = level.teams; + _k109 = getFirstArrayKey( _a109 ); + while ( isDefined( _k109 ) ) + { + team = _a109[ _k109 ]; + setobjectivetext( team, &"OBJECTIVES_CONF" ); + setobjectivehinttext( team, &"OBJECTIVES_CONF_HINT" ); + if ( level.splitscreen ) + { + setobjectivescoretext( team, &"OBJECTIVES_CONF" ); + } + else + { + setobjectivescoretext( team, &"OBJECTIVES_CONF_SCORE" ); + } + maps/mp/gametypes/_spawnlogic::placespawnpoints( maps/mp/gametypes/_spawning::gettdmstartspawnname( team ) ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( team, "mp_tdm_spawn" ); + _k109 = getNextArrayKey( _a109, _k109 ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.spawn_start = []; + _a131 = level.teams; + _k131 = getFirstArrayKey( _a131 ); + while ( isDefined( _k131 ) ) + { + team = _a131[ _k131 ]; + level.spawn_start[ team ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( maps/mp/gametypes/_spawning::gettdmstartspawnname( team ) ); + _k131 = getNextArrayKey( _a131, _k131 ); + } + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.dogtags = []; + if ( !isoneround() ) + { + level.displayroundendtext = 1; + if ( isscoreroundbased() ) + { + maps/mp/gametypes/_globallogic_score::resetteamscores(); + } + } +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( !isplayer( attacker ) || attacker.team == self.team ) + { + return; + } + level thread spawndogtags( self, attacker ); + attacker maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( attacker.team, level.teamscoreperkill ); +} + +spawndogtags( victim, attacker ) +{ + if ( isDefined( level.dogtags[ victim.entnum ] ) ) + { + playfx( level.conf_fx[ "vanish" ], level.dogtags[ victim.entnum ].curorigin ); + level.dogtags[ victim.entnum ] notify( "reset" ); + } + else + { + visuals[ 0 ] = spawn( "script_model", ( 0, 0, 1 ) ); + visuals[ 0 ] setmodel( "p6_dogtags" ); + visuals[ 1 ] = spawn( "script_model", ( 0, 0, 1 ) ); + visuals[ 1 ] setmodel( "p6_dogtags_friend" ); + trigger = spawn( "trigger_radius", ( 0, 0, 1 ), 0, 32, 32 ); + level.dogtags[ victim.entnum ] = maps/mp/gametypes/_gameobjects::createuseobject( "any", trigger, visuals, vectorScale( ( 0, 0, 1 ), 16 ) ); + _a189 = level.teams; + _k189 = getFirstArrayKey( _a189 ); + while ( isDefined( _k189 ) ) + { + team = _a189[ _k189 ]; + objective_delete( level.dogtags[ victim.entnum ].objid[ team ] ); + maps/mp/gametypes/_gameobjects::releaseobjid( level.dogtags[ victim.entnum ].objid[ team ] ); + maps/mp/gametypes/_objpoints::deleteobjpoint( level.dogtags[ victim.entnum ].objpoints[ team ] ); + _k189 = getNextArrayKey( _a189, _k189 ); + } + level.dogtags[ victim.entnum ] maps/mp/gametypes/_gameobjects::setusetime( 0 ); + level.dogtags[ victim.entnum ].onuse = ::onuse; + level.dogtags[ victim.entnum ].victim = victim; + level.dogtags[ victim.entnum ].victimteam = victim.team; + level.dogtags[ victim.entnum ].objid = maps/mp/gametypes/_gameobjects::getnextobjid(); + objective_add( level.dogtags[ victim.entnum ].objid, "invisible", ( 0, 0, 1 ) ); + objective_icon( level.dogtags[ victim.entnum ].objid, "waypoint_dogtags" ); + level thread clearonvictimdisconnect( victim ); + victim thread tagteamupdater( level.dogtags[ victim.entnum ] ); + } + pos = victim.origin + vectorScale( ( 0, 0, 1 ), 14 ); + level.dogtags[ victim.entnum ].curorigin = pos; + level.dogtags[ victim.entnum ].trigger.origin = pos; + level.dogtags[ victim.entnum ].visuals[ 0 ].origin = pos; + level.dogtags[ victim.entnum ].visuals[ 1 ].origin = pos; + level.dogtags[ victim.entnum ] maps/mp/gametypes/_gameobjects::allowuse( "any" ); + level.dogtags[ victim.entnum ].visuals[ 0 ] thread showtoteam( level.dogtags[ victim.entnum ], attacker.team ); + level.dogtags[ victim.entnum ].visuals[ 1 ] thread showtoenemyteams( level.dogtags[ victim.entnum ], attacker.team ); + level.dogtags[ victim.entnum ].attacker = attacker; + level.dogtags[ victim.entnum ].attackerteam = attacker.team; + level.dogtags[ victim.entnum ].unreachable = undefined; + level.dogtags[ victim.entnum ].tacinsert = 0; + objective_position( level.dogtags[ victim.entnum ].objid, pos ); + objective_state( level.dogtags[ victim.entnum ].objid, "active" ); + objective_setinvisibletoall( level.dogtags[ victim.entnum ].objid ); + objective_setvisibletoplayer( level.dogtags[ victim.entnum ].objid, attacker ); + level.dogtags[ victim.entnum ] thread bounce(); + level notify( "dogtag_spawned" ); +} + +showtoteam( gameobject, team ) +{ + gameobject endon( "death" ); + gameobject endon( "reset" ); + self hide(); + _a245 = level.players; + _k245 = getFirstArrayKey( _a245 ); + while ( isDefined( _k245 ) ) + { + player = _a245[ _k245 ]; + if ( player.team == team ) + { + self showtoplayer( player ); + } + _k245 = getNextArrayKey( _a245, _k245 ); + } + for ( ;; ) + { + level waittill( "joined_team" ); + self hide(); + _a256 = level.players; + _k256 = getFirstArrayKey( _a256 ); + while ( isDefined( _k256 ) ) + { + player = _a256[ _k256 ]; + if ( player.team == team ) + { + self showtoplayer( player ); + } + if ( gameobject.victimteam == player.team && player == gameobject.attacker ) + { + objective_state( gameobject.objid, "invisible" ); + } + _k256 = getNextArrayKey( _a256, _k256 ); + } + } +} + +showtoenemyteams( gameobject, friend_team ) +{ + gameobject endon( "death" ); + gameobject endon( "reset" ); + self hide(); + _a274 = level.players; + _k274 = getFirstArrayKey( _a274 ); + while ( isDefined( _k274 ) ) + { + player = _a274[ _k274 ]; + if ( player.team != friend_team ) + { + self showtoplayer( player ); + } + _k274 = getNextArrayKey( _a274, _k274 ); + } + for ( ;; ) + { + level waittill( "joined_team" ); + self hide(); + _a285 = level.players; + _k285 = getFirstArrayKey( _a285 ); + while ( isDefined( _k285 ) ) + { + player = _a285[ _k285 ]; + if ( player.team != friend_team ) + { + self showtoplayer( player ); + } + if ( gameobject.victimteam == player.team && player == gameobject.attacker ) + { + objective_state( gameobject.objid, "invisible" ); + } + _k285 = getNextArrayKey( _a285, _k285 ); + } + } +} + +onuse( player ) +{ + tacinsertboost = 0; + if ( player.team != self.attackerteam ) + { + self.trigger playsound( "mpl_killconfirm_tags_pickup" ); + player addplayerstat( "KILLSDENIED", 1 ); + player recordgameevent( "return" ); + if ( self.victim == player ) + { + if ( self.tacinsert == 0 ) + { + event = "retrieve_own_tags"; + splash = &"SPLASHES_TAGS_RETRIEVED"; + } + else + { + tacinsertboost = 1; + } + } + else + { + event = "kill_denied"; + splash = &"SPLASHES_KILL_DENIED"; + } + if ( isDefined( self.attacker ) && self.attacker.team == self.attackerteam ) + { + self.attacker luinotifyevent( &"player_callout", 2, &"MP_KILL_DENIED", player.entnum ); + self.attacker playlocalsound( game[ "dialog" ][ "kc_denied" ] ); + } + if ( !tacinsertboost ) + { + player maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "kc_deny" ); + player maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( player.team, level.teamscoreperkilldenied ); + player.pers[ "killsdenied" ]++; + player.killsdenied = player.pers[ "killsdenied" ]; + } + } + else + { + self.trigger playsound( "mpl_killconfirm_tags_pickup" ); + event = "kill_confirmed"; + splash = &"SPLASHES_KILL_CONFIRMED"; + player addplayerstat( "KILLSCONFIRMED", 1 ); + player recordgameevent( "capture" ); +/# + assert( isDefined( player.lastkillconfirmedtime ) ); + assert( isDefined( player.lastkillconfirmedcount ) ); +#/ + if ( self.attacker != player ) + { + self.attacker thread onpickup( "teammate_kill_confirmed", splash ); + } + player maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "kc_start" ); + player.pers[ "killsconfirmed" ]++; + player.killsconfirmed = player.pers[ "killsconfirmed" ]; + player maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( player.team, level.teamscoreperkillconfirmed ); + } + if ( !tacinsertboost ) + { + player thread onpickup( event, splash ); + currenttime = getTime(); + if ( ( player.lastkillconfirmedtime + 1000 ) > currenttime ) + { + player.lastkillconfirmedcount++; + if ( player.lastkillconfirmedcount >= 3 ) + { + maps/mp/_scoreevents::processscoreevent( "kill_confirmed_multi", player ); + player.lastkillconfirmedcount = 0; + } + } + else + { + player.lastkillconfirmedcount = 1; + } + player.lastkillconfirmedtime = currenttime; + } + self resettags(); +} + +onpickup( event, splash ) +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + while ( !isDefined( self.pers ) ) + { + wait 0,05; + } + maps/mp/_scoreevents::processscoreevent( event, self ); +} + +resettags() +{ + self.attacker = undefined; + self.unreachable = undefined; + self notify( "reset" ); + self.visuals[ 0 ] hide(); + self.visuals[ 1 ] hide(); + self.curorigin = vectorScale( ( 0, 0, 1 ), 1000 ); + self.trigger.origin = vectorScale( ( 0, 0, 1 ), 1000 ); + self.visuals[ 0 ].origin = vectorScale( ( 0, 0, 1 ), 1000 ); + self.visuals[ 1 ].origin = vectorScale( ( 0, 0, 1 ), 1000 ); + self.tacinsert = 0; + self maps/mp/gametypes/_gameobjects::allowuse( "none" ); + objective_state( self.objid, "invisible" ); +} + +bounce() +{ + level endon( "game_ended" ); + self endon( "reset" ); + bottompos = self.curorigin; + toppos = self.curorigin + vectorScale( ( 0, 0, 1 ), 12 ); + while ( 1 ) + { + self.visuals[ 0 ] moveto( toppos, 0,5, 0,15, 0,15 ); + self.visuals[ 0 ] rotateyaw( 180, 0,5 ); + self.visuals[ 1 ] moveto( toppos, 0,5, 0,15, 0,15 ); + self.visuals[ 1 ] rotateyaw( 180, 0,5 ); + wait 0,5; + self.visuals[ 0 ] moveto( bottompos, 0,5, 0,15, 0,15 ); + self.visuals[ 0 ] rotateyaw( 180, 0,5 ); + self.visuals[ 1 ] moveto( bottompos, 0,5, 0,15, 0,15 ); + self.visuals[ 1 ] rotateyaw( 180, 0,5 ); + wait 0,5; + } +} + +timeout( victim ) +{ + level endon( "game_ended" ); + victim endon( "disconnect" ); + self notify( "timeout" ); + self endon( "timeout" ); + level maps/mp/gametypes/_hostmigration::waitlongdurationwithhostmigrationpause( 30 ); + self.visuals[ 0 ] hide(); + self.visuals[ 1 ] hide(); + self.curorigin = vectorScale( ( 0, 0, 1 ), 1000 ); + self.trigger.origin = vectorScale( ( 0, 0, 1 ), 1000 ); + self.visuals[ 0 ].origin = vectorScale( ( 0, 0, 1 ), 1000 ); + self.visuals[ 1 ].origin = vectorScale( ( 0, 0, 1 ), 1000 ); + self.tacinsert = 0; + self maps/mp/gametypes/_gameobjects::allowuse( "none" ); +} + +tagteamupdater( tags ) +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "joined_team" ); + tags.victimteam = self.team; + tags resettags(); + } +} + +clearonvictimdisconnect( victim ) +{ + level endon( "game_ended" ); + guid = victim.entnum; + victim waittill( "disconnect" ); + if ( isDefined( level.dogtags[ guid ] ) ) + { + level.dogtags[ guid ] maps/mp/gametypes/_gameobjects::allowuse( "none" ); + playfx( level.conf_fx[ "vanish" ], level.dogtags[ guid ].curorigin ); + level.dogtags[ guid ] notify( "reset" ); + wait 0,05; + if ( isDefined( level.dogtags[ guid ] ) ) + { + objective_delete( level.dogtags[ guid ].objid ); + level.dogtags[ guid ].trigger delete(); + i = 0; + while ( i < level.dogtags[ guid ].visuals.size ) + { + level.dogtags[ guid ].visuals[ i ] delete(); + i++; + } + level.dogtags[ guid ] notify( "deleted" ); + } + } +} + +onspawnplayerunified() +{ + self.usingobj = undefined; + if ( level.usestartspawns && !level.ingraceperiod ) + { + level.usestartspawns = 0; + } + self.lastkillconfirmedtime = 0; + self.lastkillconfirmedcount = 0; + maps/mp/gametypes/_spawning::onspawnplayer_unified(); + if ( level.rankedmatch || level.leaguematch ) + { + if ( isDefined( self.tacticalinsertiontime ) && ( self.tacticalinsertiontime + 100 ) > getTime() ) + { + mindist = level.antiboostdistance; + mindistsqr = mindist * mindist; + distsqr = distancesquared( self.origin, level.dogtags[ self.entnum ].curorigin ); + if ( distsqr < mindistsqr ) + { + level.dogtags[ self.entnum ].tacinsert = 1; + } + } + } +} + +onspawnplayer( predictedspawn ) +{ + pixbeginevent( "TDM:onSpawnPlayer" ); + self.usingobj = undefined; + spawnteam = self.pers[ "team" ]; + if ( level.ingraceperiod ) + { + spawnpoints = maps/mp/gametypes/_spawnlogic::getspawnpointarray( maps/mp/gametypes/_spawning::gettdmstartspawnname( spawnteam ) ); + if ( !spawnpoints.size ) + { + spawnpoints = maps/mp/gametypes/_spawnlogic::getspawnpointarray( maps/mp/gametypes/_spawning::gettdmstartspawnname( spawnteam ) ); + } + if ( !spawnpoints.size ) + { + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( spawnteam ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( spawnpoints ); + } + else + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_random( spawnpoints ); + } + } + else + { + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( spawnteam ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( spawnpoints ); + } + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "tdm" ); + } + pixendevent(); +} + +onroundswitch() +{ + game[ "switchedsides" ] = !game[ "switchedsides" ]; +} + +onroundendgame( roundwinner ) +{ + return maps/mp/gametypes/_globallogic::determineteamwinnerbygamestat( "roundswon" ); +} diff --git a/patch_mp/maps/mp/gametypes/ctf.gsc b/patch_mp/maps/mp/gametypes/ctf.gsc new file mode 100644 index 0000000..3c99c2d --- /dev/null +++ b/patch_mp/maps/mp/gametypes/ctf.gsc @@ -0,0 +1,1250 @@ +#include maps/mp/gametypes/_rank; +#include maps/mp/gametypes/_globallogic_defaults; +#include maps/mp/_challenges; +#include maps/mp/_demo; +#include maps/mp/_scoreevents; +#include maps/mp/_popups; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/teams/_teams; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +main() +{ + if ( getDvar( "mapname" ) == "mp_background" ) + { + return; + } + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registertimelimit( 0, 1440 ); + registerroundlimit( 0, 10 ); + registerroundwinlimit( 0, 10 ); + registerroundswitch( 0, 9 ); + registernumlives( 0, 100 ); + registerscorelimit( 0, 5000 ); + level.scoreroundbased = getgametypesetting( "roundscorecarry" ) == 0; + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + if ( getDvar( "scr_ctf_spawnPointFacingAngle" ) == "" ) + { + setdvar( "scr_ctf_spawnPointFacingAngle", "0" ); + } + level.teambased = 1; + level.overrideteamscore = 1; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onprecachegametype = ::onprecachegametype; + level.onplayerkilled = ::onplayerkilled; + level.onroundswitch = ::onroundswitch; + level.onendgame = ::onendgame; + level.onroundendgame = ::onroundendgame; + level.gamemodespawndvars = ::ctf_gamemodespawndvars; + level.getteamkillpenalty = ::ctf_getteamkillpenalty; + level.getteamkillscore = ::ctf_getteamkillscore; + level.setmatchscorehudelemforteam = ::setmatchscorehudelemforteam; + level.shouldplayovertimeround = ::shouldplayovertimeround; + if ( !isDefined( game[ "ctf_teamscore" ] ) ) + { + game[ "ctf_teamscore" ][ "allies" ] = 0; + game[ "ctf_teamscore" ][ "axis" ] = 0; + } + game[ "dialog" ][ "gametype" ] = "ctf_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "hcctf_start"; + game[ "dialog" ][ "wetake_flag" ] = "ctf_wetake"; + game[ "dialog" ][ "theytake_flag" ] = "ctf_theytake"; + game[ "dialog" ][ "theydrop_flag" ] = "ctf_theydrop"; + game[ "dialog" ][ "wedrop_flag" ] = "ctf_wedrop"; + game[ "dialog" ][ "wereturn_flag" ] = "ctf_wereturn"; + game[ "dialog" ][ "theyreturn_flag" ] = "ctf_theyreturn"; + game[ "dialog" ][ "theycap_flag" ] = "ctf_theycap"; + game[ "dialog" ][ "wecap_flag" ] = "ctf_wecap"; + game[ "dialog" ][ "offense_obj" ] = "cap_start"; + game[ "dialog" ][ "defense_obj" ] = "cap_start"; + level.lastdialogtime = getTime(); + level thread ctf_icon_hide(); + if ( !sessionmodeissystemlink() && !sessionmodeisonlinegame() && issplitscreen() ) + { + setscoreboardcolumns( "score", "kills", "captures", "returns", "deaths" ); + } + else + { + setscoreboardcolumns( "score", "kills", "deaths", "captures", "returns" ); + } + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "ctf_flag", 0 ); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "ctf_flag_enemy", 0 ); +} + +onprecachegametype() +{ + game[ "flag_dropped_sound" ] = "mp_war_objective_lost"; + game[ "flag_recovered_sound" ] = "mp_war_objective_taken"; + precachemodel( maps/mp/teams/_teams::getteamflagmodel( "allies" ) ); + precachemodel( maps/mp/teams/_teams::getteamflagmodel( "axis" ) ); + precachemodel( maps/mp/teams/_teams::getteamflagcarrymodel( "allies" ) ); + precachemodel( maps/mp/teams/_teams::getteamflagcarrymodel( "axis" ) ); + precacheshader( maps/mp/teams/_teams::getteamflagicon( "allies" ) ); + precacheshader( maps/mp/teams/_teams::getteamflagicon( "axis" ) ); + precachestring( &"MP_FLAG_TAKEN_BY" ); + precachestring( &"MP_ENEMY_FLAG_TAKEN" ); + precachestring( &"MP_FRIENDLY_FLAG_TAKEN" ); + precachestring( &"MP_FLAG_CAPTURED_BY" ); + precachestring( &"MP_ENEMY_FLAG_CAPTURED_BY" ); + precachestring( &"MP_FLAG_RETURNED_BY" ); + precachestring( &"MP_FLAG_RETURNED" ); + precachestring( &"MP_ENEMY_FLAG_RETURNED" ); + precachestring( &"MP_FRIENDLY_FLAG_RETURNED" ); + precachestring( &"MP_YOUR_FLAG_RETURNING_IN" ); + precachestring( &"MP_ENEMY_FLAG_RETURNING_IN" ); + precachestring( &"MP_FRIENDLY_FLAG_DROPPED_BY" ); + precachestring( &"MP_FRIENDLY_FLAG_DROPPED" ); + precachestring( &"MP_ENEMY_FLAG_DROPPED" ); + precachestring( &"MP_SUDDEN_DEATH" ); + precachestring( &"MP_CAP_LIMIT_REACHED" ); + precachestring( &"MP_CTF_CANT_CAPTURE_FLAG" ); + precachestring( &"MP_CTF_OVERTIME_WIN" ); + precachestring( &"MP_CTF_OVERTIME_ROUND_1" ); + precachestring( &"MP_CTF_OVERTIME_ROUND_2_WINNER" ); + precachestring( &"MP_CTF_OVERTIME_ROUND_2_LOSER" ); + precachestring( &"MP_CTF_OVERTIME_ROUND_2_TIE" ); + precachestring( &"MPUI_CTF_OVERTIME_FASTEST_CAP_TIME" ); + precachestring( &"MPUI_CTF_OVERTIME_DEFEAT_TIMELIMIT" ); + precachestring( &"MPUI_CTF_OVERTIME_DEFEAT_DID_NOT_DEFEND" ); + precachestring( &"allies_base" ); + precachestring( &"axis_base" ); + precachestring( &"allies_flag" ); + precachestring( &"axis_flag" ); + game[ "strings" ][ "score_limit_reached" ] = &"MP_CAP_LIMIT_REACHED"; +} + +onstartgametype() +{ + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } +/# + setdebugsideswitch( game[ "switchedsides" ] ); +#/ + setclientnamemode( "auto_change" ); + maps/mp/gametypes/_globallogic_score::resetteamscores(); + setobjectivetext( "allies", &"OBJECTIVES_CTF" ); + setobjectivetext( "axis", &"OBJECTIVES_CTF" ); + if ( level.splitscreen ) + { + setobjectivescoretext( "allies", &"OBJECTIVES_CTF" ); + setobjectivescoretext( "axis", &"OBJECTIVES_CTF" ); + } + else + { + setobjectivescoretext( "allies", &"OBJECTIVES_CTF_SCORE" ); + setobjectivescoretext( "axis", &"OBJECTIVES_CTF_SCORE" ); + } + setobjectivehinttext( "allies", &"OBJECTIVES_CTF_HINT" ); + setobjectivehinttext( "axis", &"OBJECTIVES_CTF_HINT" ); + if ( isDefined( game[ "overtime_round" ] ) ) + { + [[ level._setteamscore ]]( "allies", 0 ); + [[ level._setteamscore ]]( "axis", 0 ); + registerscorelimit( 1, 1 ); + if ( isDefined( game[ "ctf_overtime_time_to_beat" ] ) ) + { + registertimelimit( game[ "ctf_overtime_time_to_beat" ] / 60000, game[ "ctf_overtime_time_to_beat" ] / 60000 ); + } + if ( game[ "overtime_round" ] == 1 ) + { + setobjectivehinttext( "allies", &"MP_CTF_OVERTIME_ROUND_1" ); + setobjectivehinttext( "axis", &"MP_CTF_OVERTIME_ROUND_1" ); + } + else if ( isDefined( game[ "ctf_overtime_first_winner" ] ) ) + { + setobjectivehinttext( game[ "ctf_overtime_first_winner" ], &"MP_CTF_OVERTIME_ROUND_2_WINNER" ); + setobjectivehinttext( getotherteam( game[ "ctf_overtime_first_winner" ] ), &"MP_CTF_OVERTIME_ROUND_2_LOSER" ); + } + else + { + setobjectivehinttext( "allies", &"MP_CTF_OVERTIME_ROUND_2_TIE" ); + setobjectivehinttext( "axis", &"MP_CTF_OVERTIME_ROUND_2_TIE" ); + } + } + allowed[ 0 ] = "ctf"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, -1 ); + level.spawnmaxs = ( 0, 0, -1 ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_ctf_spawn_allies_start" ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_ctf_spawn_axis_start" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_ctf_spawn_allies" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_ctf_spawn_axis" ); + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.spawn_axis = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_ctf_spawn_axis" ); + level.spawn_allies = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_ctf_spawn_allies" ); + level.spawn_start = []; + _a256 = level.teams; + _k256 = getFirstArrayKey( _a256 ); + while ( isDefined( _k256 ) ) + { + team = _a256[ _k256 ]; + level.spawn_start[ team ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_ctf_spawn_" + team + "_start" ); + _k256 = getNextArrayKey( _a256, _k256 ); + } + thread updategametypedvars(); + thread ctf(); +} + +shouldplayovertimeround() +{ + if ( isDefined( game[ "overtime_round" ] ) ) + { + if ( game[ "overtime_round" ] == 1 || !level.gameended ) + { + return 1; + } + return 0; + } + if ( level.roundscorecarry ) + { + if ( game[ "teamScores" ][ "allies" ] == game[ "teamScores" ][ "axis" ] || hitroundlimit() && game[ "teamScores" ][ "allies" ] == ( level.scorelimit - 1 ) ) + { + return 1; + } + } + else + { + alliesroundswon = getroundswon( "allies" ); + axisroundswon = getroundswon( "axis" ); + if ( level.roundwinlimit > 0 && axisroundswon == ( level.roundwinlimit - 1 ) && alliesroundswon == ( level.roundwinlimit - 1 ) ) + { + return 1; + } + if ( hitroundlimit() && alliesroundswon == axisroundswon ) + { + return 1; + } + } + return 0; +} + +minutesandsecondsstring( milliseconds ) +{ + minutes = floor( milliseconds / 60000 ); + milliseconds -= minutes * 60000; + seconds = floor( milliseconds / 1000 ); + if ( seconds < 10 ) + { + return ( minutes + ":0" ) + seconds; + } + else + { + return ( minutes + ":" ) + seconds; + } +} + +setmatchscorehudelemforteam( team ) +{ + if ( !isDefined( game[ "overtime_round" ] ) ) + { + self maps/mp/gametypes/_hud_message::setmatchscorehudelemforteam( team ); + } + else if ( isDefined( game[ "ctf_overtime_second_winner" ] ) && game[ "ctf_overtime_second_winner" ] == team ) + { + self settext( minutesandsecondsstring( game[ "ctf_overtime_best_time" ] ) ); + } + else + { + if ( isDefined( game[ "ctf_overtime_first_winner" ] ) && game[ "ctf_overtime_first_winner" ] == team ) + { + self settext( minutesandsecondsstring( game[ "ctf_overtime_time_to_beat" ] ) ); + return; + } + else + { + self settext( &"" ); + } + } +} + +onroundswitch() +{ + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + level.halftimetype = "halftime"; + game[ "switchedsides" ] = !game[ "switchedsides" ]; +} + +onendgame( winningteam ) +{ + if ( isDefined( game[ "overtime_round" ] ) ) + { + if ( game[ "overtime_round" ] == 1 ) + { + if ( isDefined( winningteam ) && winningteam != "tie" ) + { + game[ "ctf_overtime_first_winner" ] = winningteam; + game[ "ctf_overtime_time_to_beat" ] = maps/mp/gametypes/_globallogic_utils::gettimepassed(); + } + return; + } + else + { + game[ "ctf_overtime_second_winner" ] = winningteam; + game[ "ctf_overtime_best_time" ] = maps/mp/gametypes/_globallogic_utils::gettimepassed(); + } + } +} + +onroundendgame( winningteam ) +{ + if ( isDefined( game[ "overtime_round" ] ) ) + { + if ( isDefined( game[ "ctf_overtime_first_winner" ] ) ) + { + if ( !isDefined( winningteam ) || winningteam == "tie" ) + { + winningteam = game[ "ctf_overtime_first_winner" ]; + } + if ( game[ "ctf_overtime_first_winner" ] == winningteam ) + { + level.endvictoryreasontext = &"MPUI_CTF_OVERTIME_FASTEST_CAP_TIME"; + level.enddefeatreasontext = &"MPUI_CTF_OVERTIME_DEFEAT_TIMELIMIT"; + } + else + { + level.endvictoryreasontext = &"MPUI_CTF_OVERTIME_FASTEST_CAP_TIME"; + level.enddefeatreasontext = &"MPUI_CTF_OVERTIME_DEFEAT_DID_NOT_DEFEND"; + } + } + else + { + if ( !isDefined( winningteam ) || winningteam == "tie" ) + { + return "tie"; + } + } + return winningteam; + } + if ( level.roundscorecarry == 0 ) + { + _a402 = level.teams; + _k402 = getFirstArrayKey( _a402 ); + while ( isDefined( _k402 ) ) + { + team = _a402[ _k402 ]; + [[ level._setteamscore ]]( team, game[ "roundswon" ][ team ] ); + _k402 = getNextArrayKey( _a402, _k402 ); + } + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbygamestat( "roundswon" ); + } + else + { + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbyteamscore(); + } + return winner; +} + +onspawnplayerunified() +{ + self.isflagcarrier = 0; + self.flagcarried = undefined; + self clearclientflag( 0 ); + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + self.isflagcarrier = 0; + self.flagcarried = undefined; + self clearclientflag( 0 ); + spawnteam = self.pers[ "team" ]; + if ( game[ "switchedsides" ] ) + { + spawnteam = getotherteam( spawnteam ); + } + if ( level.usestartspawns ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_random( level.spawn_start[ spawnteam ] ); + } + else if ( spawnteam == "axis" ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_axis ); + } + else + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_allies ); + } +/# + assert( isDefined( spawnpoint ) ); +#/ + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "ctf" ); + } +} + +updategametypedvars() +{ + level.flagcapturetime = getgametypesetting( "captureTime" ); + level.flagtouchreturntime = getgametypesetting( "defuseTime" ); + level.idleflagreturntime = getgametypesetting( "idleFlagResetTime" ); + level.flagrespawntime = getgametypesetting( "flagRespawnTime" ); + level.enemycarriervisible = getgametypesetting( "enemyCarrierVisible" ); + level.roundlimit = getgametypesetting( "roundLimit" ); + level.roundscorecarry = getgametypesetting( "roundscorecarry" ); + level.teamkillpenaltymultiplier = getgametypesetting( "teamKillPenalty" ); + level.teamkillscoremultiplier = getgametypesetting( "teamKillScore" ); + if ( level.flagtouchreturntime >= 0 && level.flagtouchreturntime != 63 ) + { + level.touchreturn = 1; + } + else + { + level.touchreturn = 0; + } +} + +createflag( trigger ) +{ + if ( isDefined( trigger.target ) ) + { + visuals[ 0 ] = getent( trigger.target, "targetname" ); + } + else + { + visuals[ 0 ] = spawn( "script_model", trigger.origin ); + visuals[ 0 ].angles = trigger.angles; + } + entityteam = trigger.script_team; + if ( game[ "switchedsides" ] ) + { + entityteam = getotherteam( entityteam ); + } + visuals[ 0 ] setmodel( maps/mp/teams/_teams::getteamflagmodel( entityteam ) ); + visuals[ 0 ] setteam( entityteam ); + flag = maps/mp/gametypes/_gameobjects::createcarryobject( entityteam, trigger, visuals, vectorScale( ( 0, 0, -1 ), 100 ), istring( entityteam + "_flag" ) ); + flag maps/mp/gametypes/_gameobjects::setteamusetime( "friendly", level.flagtouchreturntime ); + flag maps/mp/gametypes/_gameobjects::setteamusetime( "enemy", level.flagcapturetime ); + flag maps/mp/gametypes/_gameobjects::allowcarry( "enemy" ); + flag maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + flag maps/mp/gametypes/_gameobjects::setvisiblecarriermodel( maps/mp/teams/_teams::getteamflagcarrymodel( entityteam ) ); + flag maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.icondefend2d ); + flag maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.icondefend3d ); + flag maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconcapture2d ); + flag maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconcapture3d ); + flag maps/mp/gametypes/_gameobjects::setcarryicon( maps/mp/teams/_teams::getteamflagicon( entityteam ) ); + if ( level.enemycarriervisible == 2 ) + { + flag.objidpingfriendly = 1; + } + flag.allowweapons = 1; + flag.onpickup = ::onpickup; + flag.onpickupfailed = ::onpickup; + flag.ondrop = ::ondrop; + flag.onreset = ::onreset; + if ( level.idleflagreturntime > 0 ) + { + flag.autoresettime = level.idleflagreturntime; + } + else + { + flag.autoresettime = undefined; + } + return flag; +} + +createflagzone( trigger ) +{ + visuals = []; + entityteam = trigger.script_team; + if ( game[ "switchedsides" ] ) + { + entityteam = getotherteam( entityteam ); + } + flagzone = maps/mp/gametypes/_gameobjects::createuseobject( entityteam, trigger, visuals, ( 0, 0, -1 ), istring( entityteam + "_base" ) ); + flagzone maps/mp/gametypes/_gameobjects::allowuse( "friendly" ); + flagzone maps/mp/gametypes/_gameobjects::setusetime( 0 ); + flagzone maps/mp/gametypes/_gameobjects::setusetext( &"MP_CAPTURING_FLAG" ); + flagzone maps/mp/gametypes/_gameobjects::setvisibleteam( "friendly" ); + enemyteam = getotherteam( entityteam ); + flagzone maps/mp/gametypes/_gameobjects::setkeyobject( level.teamflags[ enemyteam ] ); + flagzone.onuse = ::oncapture; + flag = level.teamflags[ entityteam ]; + flag.flagbase = flagzone; + flagzone.flag = flag; + tracestart = trigger.origin + vectorScale( ( 0, 0, -1 ), 32 ); + traceend = trigger.origin + vectorScale( ( 0, 0, -1 ), 32 ); + trace = bullettrace( tracestart, traceend, 0, undefined ); + upangles = vectorToAngle( trace[ "normal" ] ); + flagzone.baseeffectforward = anglesToForward( upangles ); + flagzone.baseeffectright = anglesToRight( upangles ); + flagzone.baseeffectpos = trace[ "position" ]; + flagzone thread resetflagbaseeffect(); + flagzone createflagspawninfluencer( entityteam ); + return flagzone; +} + +createflaghint( team, origin ) +{ + radius = 128; + height = 64; + trigger = spawn( "trigger_radius", origin, 0, radius, height ); + trigger sethintstring( &"MP_CTF_CANT_CAPTURE_FLAG" ); + trigger setcursorhint( "HINT_NOICON" ); + trigger.original_origin = origin; + trigger turn_off(); + return trigger; +} + +ctf() +{ + level.flags = []; + level.teamflags = []; + level.flagzones = []; + level.teamflagzones = []; + level.iconcapture3d = "waypoint_grab_red"; + level.iconcapture2d = "waypoint_grab_red"; + level.icondefend3d = "waypoint_defend_flag"; + level.icondefend2d = "waypoint_defend_flag"; + level.icondropped3d = "waypoint_defend_flag"; + level.icondropped2d = "waypoint_defend_flag"; + level.iconreturn3d = "waypoint_return_flag"; + level.iconreturn2d = "waypoint_return_flag"; + level.iconbase3d = "waypoint_defend_flag"; + level.iconescort3d = "waypoint_escort"; + level.iconescort2d = "waypoint_escort"; + level.iconkill3d = "waypoint_kill"; + level.iconkill2d = "waypoint_kill"; + level.iconwaitforflag3d = "waypoint_waitfor_flag"; + precacheshader( level.iconcapture3d ); + precacheshader( level.iconcapture2d ); + precacheshader( level.icondefend3d ); + precacheshader( level.icondefend2d ); + precacheshader( level.icondropped3d ); + precacheshader( level.icondropped2d ); + precacheshader( level.iconbase3d ); + precacheshader( level.iconreturn3d ); + precacheshader( level.iconreturn2d ); + precacheshader( level.iconescort3d ); + precacheshader( level.iconescort2d ); + precacheshader( level.iconkill3d ); + precacheshader( level.iconkill2d ); + precacheshader( level.iconwaitforflag3d ); + level.flagbasefxid = []; + level.flagbasefxid[ "allies" ] = loadfx( "misc/fx_ui_flagbase_" + game[ "allies" ] ); + level.flagbasefxid[ "axis" ] = loadfx( "misc/fx_ui_flagbase_" + game[ "axis" ] ); + flag_triggers = getentarray( "ctf_flag_pickup_trig", "targetname" ); + if ( !isDefined( flag_triggers ) || flag_triggers.size != 2 ) + { +/# + maps/mp/_utility::error( "Not enough ctf_flag_pickup_trig triggers found in map. Need two." ); +#/ + return; + } + index = 0; + while ( index < flag_triggers.size ) + { + trigger = flag_triggers[ index ]; + flag = createflag( trigger ); + team = flag maps/mp/gametypes/_gameobjects::getownerteam(); + level.flags[ level.flags.size ] = flag; + level.teamflags[ team ] = flag; + index++; + } + flag_zones = getentarray( "ctf_flag_zone_trig", "targetname" ); + if ( !isDefined( flag_zones ) || flag_zones.size != 2 ) + { +/# + maps/mp/_utility::error( "Not enough ctf_flag_zone_trig triggers found in map. Need two." ); +#/ + return; + } + index = 0; + while ( index < flag_zones.size ) + { + trigger = flag_zones[ index ]; + flagzone = createflagzone( trigger ); + team = flagzone maps/mp/gametypes/_gameobjects::getownerteam(); + level.flagzones[ level.flagzones.size ] = flagzone; + level.teamflagzones[ team ] = flagzone; + level.flaghints[ team ] = createflaghint( team, trigger.origin ); + facing_angle = getDvarInt( "scr_ctf_spawnPointFacingAngle" ); + setspawnpointsbaseweight( getotherteamsmask( team ), trigger.origin, facing_angle, level.spawnsystem.objective_facing_bonus ); + index++; + } + createreturnmessageelems(); +} + +ctf_icon_hide() +{ + level waittill( "game_ended" ); + level.teamflags[ "allies" ] maps/mp/gametypes/_gameobjects::setvisibleteam( "none" ); + level.teamflags[ "axis" ] maps/mp/gametypes/_gameobjects::setvisibleteam( "none" ); +} + +removeinfluencers() +{ + if ( isDefined( self.spawn_influencer_enemy_carrier ) ) + { + removeinfluencer( self.spawn_influencer_enemy_carrier ); + self.spawn_influencer_enemy_carrier = undefined; + } + if ( isDefined( self.spawn_influencer_friendly_carrier ) ) + { + removeinfluencer( self.spawn_influencer_friendly_carrier ); + self.spawn_influencer_friendly_carrier = undefined; + } + if ( isDefined( self.spawn_influencer_dropped ) ) + { + removeinfluencer( self.spawn_influencer_dropped ); + self.spawn_influencer_dropped = undefined; + } +} + +ondrop( player ) +{ + if ( isDefined( player ) ) + { + player clearclientflag( 0 ); + } + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + otherteam = getotherteam( team ); + bbprint( "mpobjective", "gametime %d objtype %s team %s", getTime(), "ctf_flagdropped", team ); + self.visuals[ 0 ] setclientflag( 6 ); + if ( level.touchreturn ) + { + self maps/mp/gametypes/_gameobjects::allowcarry( "any" ); + level.flaghints[ otherteam ] turn_off(); + } + if ( isDefined( player ) ) + { + printandsoundoneveryone( team, undefined, &"", undefined, "mp_war_objective_lost" ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_FRIENDLY_FLAG_DROPPED", player, team ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_ENEMY_FLAG_DROPPED", player, otherteam ); + } + else + { + printandsoundoneveryone( team, undefined, &"", undefined, "mp_war_objective_lost" ); + } + maps/mp/gametypes/_globallogic_audio::leaderdialog( "wedrop_flag", otherteam, "ctf_flag" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "theydrop_flag", team, "ctf_flag_enemy" ); + if ( isDefined( player ) ) + { + player logstring( team + " flag dropped" ); + } + else + { + logstring( team + " flag dropped" ); + } + if ( isDefined( player ) ) + { + player playlocalsound( "mpl_flag_drop_plr" ); + } + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagdrop_sting_friend", otherteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagdrop_sting_enemy", team ); + if ( level.touchreturn ) + { + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.iconreturn3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.iconreturn2d ); + } + else + { + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.icondropped3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.icondropped2d ); + } + self maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconcapture3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconcapture2d ); + thread maps/mp/_utility::playsoundonplayers( game[ "flag_dropped_sound" ], game[ "attackers" ] ); + self thread returnflagaftertimemsg( level.idleflagreturntime ); + if ( isDefined( player ) ) + { + self removeinfluencers(); + } + else + { + self.spawn_influencer_friendly_carrier = undefined; + self.spawn_influencer_enemy_carrier = undefined; + } + ss = level.spawnsystem; + player_team_mask = getteammask( otherteam ); + enemy_team_mask = getteammask( team ); + if ( isDefined( player ) ) + { + flag_origin = player.origin; + } + else + { + flag_origin = self.curorigin; + } + self.spawn_influencer_dropped = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, flag_origin, ss.ctf_dropped_influencer_radius, ss.ctf_dropped_influencer_score, player_team_mask | enemy_team_mask, "ctf_flag_dropped,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ss.ctf_dropped_influencer_score_curve ), level.idleflagreturntime, self.trigger ); +} + +onpickup( player ) +{ + carrierkilledby = self.carrierkilledby; + self.carrierkilledby = undefined; + if ( isDefined( self.spawn_influencer_dropped ) ) + { + removeinfluencer( self.spawn_influencer_dropped ); + self.spawn_influencer_dropped = undefined; + } + player addplayerstatwithgametype( "PICKUPS", 1 ); + if ( level.touchreturn ) + { + self maps/mp/gametypes/_gameobjects::allowcarry( "enemy" ); + } + self removeinfluencers(); + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + otherteam = getotherteam( team ); + self clearreturnflaghudelems(); + if ( isDefined( player ) && player.pers[ "team" ] == team ) + { + self notify( "picked_up" ); + printandsoundoneveryone( team, undefined, &"", undefined, "mp_obj_returned" ); + if ( isDefined( player.pers[ "returns" ] ) ) + { + player.pers[ "returns" ]++; + player.returns = player.pers[ "returns" ]; + } + if ( isDefined( carrierkilledby ) && carrierkilledby == player ) + { + maps/mp/_scoreevents::processscoreevent( "flag_carrier_kill_return_close", player ); + } + else + { + if ( distancesquared( self.trigger.baseorigin, player.origin ) > 90000 ) + { + maps/mp/_scoreevents::processscoreevent( "flag_return", player ); + } + } + maps/mp/_demo::bookmark( "event", getTime(), player ); + player addplayerstatwithgametype( "RETURNS", 1 ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_FRIENDLY_FLAG_RETURNED", player, team ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_ENEMY_FLAG_RETURNED", player, otherteam ); + self.visuals[ 0 ] clearclientflag( 6 ); + self maps/mp/gametypes/_gameobjects::setflags( 0 ); + bbprint( "mpobjective", "gametime %d objtype %s team %s", getTime(), "ctf_flagreturn", team ); + player recordgameevent( "return" ); + self returnflag(); + self maps/mp/gametypes/_gameobjects::returnhome(); + if ( isDefined( player ) ) + { + player logstring( team + " flag returned" ); + } + else + { + logstring( team + " flag returned" ); + } + return; + } + else + { + bbprint( "mpobjective", "gametime %d objtype %s team %s", getTime(), "ctf_flagpickup", team ); + player recordgameevent( "pickup" ); + maps/mp/_scoreevents::processscoreevent( "flag_grab", player ); + maps/mp/_demo::bookmark( "event", getTime(), player ); + printandsoundoneveryone( otherteam, undefined, &"", undefined, "mp_obj_taken", "mp_enemy_obj_taken" ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_FRIENDLY_FLAG_TAKEN", player, team ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_ENEMY_FLAG_TAKEN", player, otherteam ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "wetake_flag", otherteam, "ctf_flag" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "theytake_flag", team, "ctf_flag_enemy" ); + player.isflagcarrier = 1; + player.flagcarried = self; + player playlocalsound( "mpl_flag_pickup_plr" ); + player setclientflag( 0 ); + self maps/mp/gametypes/_gameobjects::setflags( 1 ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagget_sting_friend", otherteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagget_sting_enemy", team ); + if ( level.enemycarriervisible ) + { + self maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + } + else + { + self maps/mp/gametypes/_gameobjects::setvisibleteam( "enemy" ); + } + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.iconkill2d ); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.iconkill3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconescort2d ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconescort3d ); + player thread claim_trigger( level.flaghints[ otherteam ] ); + update_hints(); + player logstring( team + " flag taken" ); + ss = level.spawnsystem; + player_team_mask = getteammask( otherteam ); + enemy_team_mask = getteammask( team ); + self.spawn_influencer_enemy_carrier = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, player.origin, ss.ctf_enemy_carrier_influencer_radius, ss.ctf_enemy_carrier_influencer_score, enemy_team_mask, "ctf_flag_enemy_carrier,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ss.ctf_enemy_carrier_influencer_score_curve ), 0, player ); + self.spawn_influencer_friendly_carrier = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, player.origin, ss.ctf_friendly_carrier_influencer_radius, ss.ctf_friendly_carrier_influencer_score, player_team_mask, "ctf_flag_friendly_carrier,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ss.ctf_friendly_carrier_influencer_score_curve ), 0, player ); + } +} + +onpickupmusicstate( player ) +{ + self endon( "disconnect" ); + self endon( "death" ); + wait 6; + if ( player.isflagcarrier ) + { + } +} + +ishome() +{ + if ( isDefined( self.carrier ) ) + { + return 0; + } + if ( self.curorigin != self.trigger.baseorigin ) + { + return 0; + } + return 1; +} + +returnflag() +{ + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + otherteam = getotherteam( team ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagreturn_sting", team ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagreturn_sting", otherteam ); + level.teamflagzones[ otherteam ] maps/mp/gametypes/_gameobjects::allowuse( "friendly" ); + level.teamflagzones[ otherteam ] maps/mp/gametypes/_gameobjects::setvisibleteam( "friendly" ); + update_hints(); + if ( level.touchreturn ) + { + self maps/mp/gametypes/_gameobjects::allowcarry( "enemy" ); + } + self maps/mp/gametypes/_gameobjects::returnhome(); + self maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.icondefend3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.icondefend2d ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconcapture3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconcapture2d ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "wereturn_flag", team, "ctf_flag_enemy" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "theyreturn_flag", otherteam, "ctf_flag" ); +} + +oncapture( player ) +{ + team = player.pers[ "team" ]; + enemyteam = getotherteam( team ); + time = getTime(); + playerteamsflag = level.teamflags[ team ]; + if ( playerteamsflag maps/mp/gametypes/_gameobjects::isobjectawayfromhome() ) + { + return; + } + printandsoundoneveryone( team, undefined, &"", undefined, "mp_obj_captured", "mp_enemy_obj_captured" ); + bbprint( "mpobjective", "gametime %d objtype %s team %s", time, "ctf_flagcapture", enemyteam ); + game[ "challenge" ][ team ][ "capturedFlag" ] = 1; + player maps/mp/_challenges::capturedobjective( time ); + if ( isDefined( player.pers[ "captures" ] ) ) + { + player.pers[ "captures" ]++; + player.captures = player.pers[ "captures" ]; + } + maps/mp/_demo::bookmark( "event", getTime(), player ); + player addplayerstatwithgametype( "CAPTURES", 1 ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_ENEMY_FLAG_CAPTURED", player, team ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_FRIENDLY_FLAG_CAPTURED", player, enemyteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagcapture_sting_enemy", enemyteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagcapture_sting_friend", team ); + player giveflagcapturexp( player ); + player logstring( enemyteam + " flag captured" ); + flag = player.carryobject; + flag.dontannouncereturn = 1; + flag maps/mp/gametypes/_gameobjects::returnhome(); + flag.dontannouncereturn = undefined; + otherteam = getotherteam( team ); + level.teamflags[ otherteam ] maps/mp/gametypes/_gameobjects::allowcarry( "enemy" ); + level.teamflags[ otherteam ] maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + level.teamflags[ otherteam ] maps/mp/gametypes/_gameobjects::returnhome(); + level.teamflagzones[ otherteam ] maps/mp/gametypes/_gameobjects::allowuse( "friendly" ); + player.isflagcarrier = 0; + player.flagcarried = undefined; + player clearclientflag( 0 ); + maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( team, 1 ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "wecap_flag", team, "ctf_flag" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "theycap_flag", enemyteam, "ctf_flag_enemy" ); + flag removeinfluencers(); +} + +giveflagcapturexp( player ) +{ + maps/mp/_scoreevents::processscoreevent( "flag_capture", player ); + player recordgameevent( "capture" ); +} + +onreset() +{ + update_hints(); + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.icondefend3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.icondefend2d ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconcapture3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconcapture2d ); + if ( level.touchreturn ) + { + self maps/mp/gametypes/_gameobjects::allowcarry( "enemy" ); + } + level.teamflagzones[ team ] maps/mp/gametypes/_gameobjects::setvisibleteam( "friendly" ); + level.teamflagzones[ team ] maps/mp/gametypes/_gameobjects::allowuse( "friendly" ); + self.visuals[ 0 ] clearclientflag( 6 ); + self maps/mp/gametypes/_gameobjects::setflags( 0 ); + self clearreturnflaghudelems(); +} + +getotherflag( flag ) +{ + if ( flag == level.flags[ 0 ] ) + { + return level.flags[ 1 ]; + } + return level.flags[ 0 ]; +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + while ( isDefined( attacker ) && isplayer( attacker ) ) + { + index = 0; + while ( index < level.flags.size ) + { + flagteam = "invalidTeam"; + inflagzone = 0; + defendedflag = 0; + offendedflag = 0; + flagcarrier = level.flags[ index ].carrier; + if ( isDefined( flagcarrier ) ) + { + flagorigin = level.flags[ index ].carrier.origin; + iscarried = 1; + if ( isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + if ( isDefined( level.flags[ index ].carrier.attackerdata ) ) + { + if ( level.flags[ index ].carrier != attacker ) + { + if ( isDefined( level.flags[ index ].carrier.attackerdata[ self.clientid ] ) ) + { + maps/mp/_scoreevents::processscoreevent( "rescue_flag_carrier", attacker, undefined, sweapon ); + } + } + } + } + } + else + { + flagorigin = level.flags[ index ].curorigin; + iscarried = 0; + } + dist = distance2d( self.origin, flagorigin ); + if ( dist < level.defaultoffenseradius ) + { + inflagzone = 1; + if ( level.flags[ index ].ownerteam == attacker.pers[ "team" ] ) + { + defendedflag = 1; + break; + } + else + { + offendedflag = 1; + } + } + dist = distance2d( attacker.origin, flagorigin ); + if ( dist < level.defaultoffenseradius ) + { + inflagzone = 1; + if ( level.flags[ index ].ownerteam == attacker.pers[ "team" ] ) + { + defendedflag = 1; + break; + } + else + { + offendedflag = 1; + } + } + if ( inflagzone && isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + if ( defendedflag ) + { + attacker addplayerstatwithgametype( "DEFENDS", 1 ); + if ( isDefined( self.isflagcarrier ) && self.isflagcarrier ) + { + maps/mp/_scoreevents::processscoreevent( "kill_flag_carrier", attacker, undefined, sweapon ); + } + else + { + maps/mp/_scoreevents::processscoreevent( "killed_attacker", attacker, undefined, sweapon ); + } + self recordkillmodifier( "assaulting" ); + } + if ( offendedflag ) + { + attacker addplayerstatwithgametype( "OFFENDS", 1 ); + if ( iscarried == 1 ) + { + if ( isDefined( flagcarrier ) && attacker == flagcarrier ) + { + maps/mp/_scoreevents::processscoreevent( "killed_enemy_while_carrying_flag", attacker, undefined, sweapon ); + } + else + { + maps/mp/_scoreevents::processscoreevent( "defend_flag_carrier", attacker, undefined, sweapon ); + } + } + else + { + maps/mp/_scoreevents::processscoreevent( "killed_defender", attacker, undefined, sweapon ); + } + self recordkillmodifier( "defending" ); + } + } + index++; + } + } + if ( !isDefined( self.isflagcarrier ) || !self.isflagcarrier ) + { + return; + } + if ( isDefined( attacker ) && isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + while ( isDefined( self.flagcarried ) ) + { + index = 0; + while ( index < level.flags.size ) + { + currentflag = level.flags[ index ]; + if ( currentflag.ownerteam == self.team ) + { + if ( currentflag.curorigin == currentflag.trigger.baseorigin ) + { + dist = distance2d( self.origin, currentflag.curorigin ); + if ( dist < level.defaultoffenseradius ) + { + self.flagcarried.carrierkilledby = attacker; + break; + } + } + } + else + { + index++; + } + } + } + attacker recordgameevent( "kill_carrier" ); + self recordkillmodifier( "carrying" ); + } +} + +createreturnmessageelems() +{ + level.returnmessageelems = []; + level.returnmessageelems[ "allies" ][ "axis" ] = createservertimer( "objective", 1,4, "allies" ); + level.returnmessageelems[ "allies" ][ "axis" ] setpoint( "TOPRIGHT", "TOPRIGHT", 0, 0 ); + level.returnmessageelems[ "allies" ][ "axis" ].label = &"MP_ENEMY_FLAG_RETURNING_IN"; + level.returnmessageelems[ "allies" ][ "axis" ].alpha = 0; + level.returnmessageelems[ "allies" ][ "axis" ].archived = 0; + level.returnmessageelems[ "allies" ][ "allies" ] = createservertimer( "objective", 1,4, "allies" ); + level.returnmessageelems[ "allies" ][ "allies" ] setpoint( "TOPRIGHT", "TOPRIGHT", 0, 20 ); + level.returnmessageelems[ "allies" ][ "allies" ].label = &"MP_YOUR_FLAG_RETURNING_IN"; + level.returnmessageelems[ "allies" ][ "allies" ].alpha = 0; + level.returnmessageelems[ "allies" ][ "allies" ].archived = 0; + level.returnmessageelems[ "axis" ][ "allies" ] = createservertimer( "objective", 1,4, "axis" ); + level.returnmessageelems[ "axis" ][ "allies" ] setpoint( "TOPRIGHT", "TOPRIGHT", 0, 0 ); + level.returnmessageelems[ "axis" ][ "allies" ].label = &"MP_ENEMY_FLAG_RETURNING_IN"; + level.returnmessageelems[ "axis" ][ "allies" ].alpha = 0; + level.returnmessageelems[ "axis" ][ "allies" ].archived = 0; + level.returnmessageelems[ "axis" ][ "axis" ] = createservertimer( "objective", 1,4, "axis" ); + level.returnmessageelems[ "axis" ][ "axis" ] setpoint( "TOPRIGHT", "TOPRIGHT", 0, 20 ); + level.returnmessageelems[ "axis" ][ "axis" ].label = &"MP_YOUR_FLAG_RETURNING_IN"; + level.returnmessageelems[ "axis" ][ "axis" ].alpha = 0; + level.returnmessageelems[ "axis" ][ "axis" ].archived = 0; +} + +returnflagaftertimemsg( time ) +{ + if ( level.touchreturn || level.idleflagreturntime == 0 ) + { + return; + } + self notify( "returnFlagAfterTimeMsg" ); + self endon( "returnFlagAfterTimeMsg" ); + result = returnflaghudelems( time ); + self removeinfluencers(); + self clearreturnflaghudelems(); + if ( !isDefined( result ) ) + { + return; + } +} + +returnflaghudelems( time ) +{ + self endon( "picked_up" ); + level endon( "game_ended" ); + ownerteam = self maps/mp/gametypes/_gameobjects::getownerteam(); +/# + assert( !level.returnmessageelems[ "axis" ][ ownerteam ].alpha ); +#/ + level.returnmessageelems[ "axis" ][ ownerteam ].alpha = 1; + level.returnmessageelems[ "axis" ][ ownerteam ] settimer( time ); +/# + assert( !level.returnmessageelems[ "allies" ][ ownerteam ].alpha ); +#/ + level.returnmessageelems[ "allies" ][ ownerteam ].alpha = 1; + level.returnmessageelems[ "allies" ][ ownerteam ] settimer( time ); + if ( time <= 0 ) + { + return 0; + } + else + { + wait time; + } + return 1; +} + +clearreturnflaghudelems() +{ + ownerteam = self maps/mp/gametypes/_gameobjects::getownerteam(); + level.returnmessageelems[ "allies" ][ ownerteam ].alpha = 0; + level.returnmessageelems[ "axis" ][ ownerteam ].alpha = 0; +} + +resetflagbaseeffect() +{ + wait 0,1; + if ( isDefined( self.baseeffect ) ) + { + self.baseeffect delete(); + } + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + if ( team != "axis" && team != "allies" ) + { + return; + } + fxid = level.flagbasefxid[ team ]; + self.baseeffect = spawnfx( fxid, self.baseeffectpos, self.baseeffectforward, self.baseeffectright ); + triggerfx( self.baseeffect ); +} + +turn_on() +{ + if ( level.hardcoremode ) + { + return; + } + self.origin = self.original_origin; +} + +turn_off() +{ + self.origin = ( self.original_origin[ 0 ], self.original_origin[ 1 ], self.original_origin[ 2 ] - 10000 ); +} + +update_hints() +{ + allied_flag = level.teamflags[ "allies" ]; + axis_flag = level.teamflags[ "axis" ]; + if ( !level.touchreturn ) + { + return; + } + if ( isDefined( allied_flag.carrier ) && axis_flag maps/mp/gametypes/_gameobjects::isobjectawayfromhome() ) + { + level.flaghints[ "axis" ] turn_on(); + } + else + { + level.flaghints[ "axis" ] turn_off(); + } + if ( isDefined( axis_flag.carrier ) && allied_flag maps/mp/gametypes/_gameobjects::isobjectawayfromhome() ) + { + level.flaghints[ "allies" ] turn_on(); + } + else + { + level.flaghints[ "allies" ] turn_off(); + } +} + +claim_trigger( trigger ) +{ + self endon( "disconnect" ); + self clientclaimtrigger( trigger ); + self waittill( "drop_object" ); + self clientreleasetrigger( trigger ); +} + +createflagspawninfluencer( entityteam ) +{ + ctf_friendly_base_influencer_score = level.spawnsystem.ctf_friendly_base_influencer_score; + ctf_friendly_base_influencer_score_curve = level.spawnsystem.ctf_friendly_base_influencer_score_curve; + ctf_friendly_base_influencer_radius = level.spawnsystem.ctf_friendly_base_influencer_radius; + ctf_enemy_base_influencer_score = level.spawnsystem.ctf_enemy_base_influencer_score; + ctf_enemy_base_influencer_score_curve = level.spawnsystem.ctf_enemy_base_influencer_score_curve; + ctf_enemy_base_influencer_radius = level.spawnsystem.ctf_enemy_base_influencer_radius; + otherteam = getotherteam( entityteam ); + team_mask = getteammask( entityteam ); + other_team_mask = getteammask( otherteam ); + self.spawn_influencer_friendly = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.trigger.origin, ctf_friendly_base_influencer_radius, ctf_friendly_base_influencer_score, team_mask, "ctf_friendly_base,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ctf_friendly_base_influencer_score_curve ) ); + self.spawn_influencer_enemy = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.trigger.origin, ctf_enemy_base_influencer_radius, ctf_enemy_base_influencer_score, other_team_mask, "ctf_enemy_base,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ctf_enemy_base_influencer_score_curve ) ); +} + +ctf_gamemodespawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.ctf_friendly_base_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_friendly_base_influencer_score", "0", reset_dvars ); + ss.ctf_friendly_base_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_friendly_base_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_friendly_base_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_friendly_base_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.ctf_enemy_base_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_enemy_base_influencer_score", "-500", reset_dvars ); + ss.ctf_enemy_base_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_enemy_base_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_enemy_base_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_enemy_base_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.ctf_enemy_carrier_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_enemy_carrier_influencer_score", "0", reset_dvars ); + ss.ctf_enemy_carrier_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_enemy_carrier_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_enemy_carrier_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_enemy_carrier_influencer_radius", "" + ( 10 * get_player_height() ), reset_dvars ); + ss.ctf_friendly_carrier_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_friendly_carrier_influencer_score", "0", reset_dvars ); + ss.ctf_friendly_carrier_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_friendly_carrier_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_friendly_carrier_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_friendly_carrier_influencer_radius", "" + ( 8 * get_player_height() ), reset_dvars ); + ss.ctf_dropped_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_dropped_influencer_score", "0", reset_dvars ); + ss.ctf_dropped_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_dropped_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_dropped_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_dropped_influencer_radius", "" + ( 10 * get_player_height() ), reset_dvars ); +} + +ctf_getteamkillpenalty( einflictor, attacker, smeansofdeath, sweapon ) +{ + teamkill_penalty = maps/mp/gametypes/_globallogic_defaults::default_getteamkillpenalty( einflictor, attacker, smeansofdeath, sweapon ); + if ( isDefined( self.isflagcarrier ) && self.isflagcarrier ) + { + teamkill_penalty *= level.teamkillpenaltymultiplier; + } + return teamkill_penalty; +} + +ctf_getteamkillscore( einflictor, attacker, smeansofdeath, sweapon ) +{ + teamkill_score = maps/mp/gametypes/_rank::getscoreinfovalue( "kill" ); + if ( isDefined( self.isflagcarrier ) && self.isflagcarrier ) + { + teamkill_score *= level.teamkillscoremultiplier; + } + return int( teamkill_score ); +} diff --git a/patch_mp/maps/mp/gametypes/dem.gsc b/patch_mp/maps/mp/gametypes/dem.gsc new file mode 100644 index 0000000..39baf51 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/dem.gsc @@ -0,0 +1,1303 @@ +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/_challenges; +#include maps/mp/_popups; +#include maps/mp/_demo; +#include maps/mp/gametypes/_battlechatter_mp; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_spectating; +#include maps/mp/_scoreevents; +#include maps/mp/_medals; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_rank; +#include maps/mp/gametypes/_globallogic_defaults; +#include maps/mp/gametypes/_hud_util; +#include common_scripts/utility; + +main() +{ + if ( getDvar( "mapname" ) == "mp_background" ) + { + return; + } + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registerroundswitch( 0, 9 ); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 500 ); + registerroundlimit( 0, 12 ); + registerroundwinlimit( 0, 10 ); + registernumlives( 0, 100 ); + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + level.teambased = 1; + level.overrideteamscore = 1; + level.onprecachegametype = ::onprecachegametype; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.playerspawnedcb = ::dem_playerspawnedcb; + level.onplayerkilled = ::onplayerkilled; + level.ondeadevent = ::ondeadevent; + level.ononeleftevent = ::ononeleftevent; + level.ontimelimit = ::ontimelimit; + level.onroundswitch = ::onroundswitch; + level.getteamkillpenalty = ::dem_getteamkillpenalty; + level.getteamkillscore = ::dem_getteamkillscore; + level.gamemodespawndvars = ::gamemodespawndvars; + level.gettimelimit = ::gettimelimit; + level.shouldplayovertimeround = ::shouldplayovertimeround; + level.lastbombexplodetime = undefined; + level.lastbombexplodebyteam = undefined; + level.ddbombmodel = []; + level.endgameonscorelimit = 0; + game[ "dialog" ][ "gametype" ] = "demo_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "hcdemo_start"; + game[ "dialog" ][ "offense_obj" ] = "destroy_start"; + game[ "dialog" ][ "defense_obj" ] = "defend_start"; + game[ "dialog" ][ "sudden_death" ] = "suddendeath"; + if ( !sessionmodeissystemlink() && !sessionmodeisonlinegame() && issplitscreen() ) + { + setscoreboardcolumns( "score", "kills", "plants", "defuses", "deaths" ); + } + else + { + setscoreboardcolumns( "score", "kills", "deaths", "plants", "defuses" ); + } +} + +onprecachegametype() +{ + game[ "bombmodelname" ] = "t5_weapon_briefcase_bomb_world"; + game[ "bombmodelnameobj" ] = "t5_weapon_briefcase_bomb_world"; + game[ "bomb_dropped_sound" ] = "mpl_flag_drop_plr"; + game[ "bomb_recovered_sound" ] = "mpl_flag_pickup_plr"; + precachemodel( game[ "bombmodelname" ] ); + precachemodel( game[ "bombmodelnameobj" ] ); + precacheshader( "waypoint_bomb" ); + precacheshader( "hud_suitcase_bomb" ); + precacheshader( "waypoint_target" ); + precacheshader( "waypoint_target_a" ); + precacheshader( "waypoint_target_b" ); + precacheshader( "waypoint_defend" ); + precacheshader( "waypoint_defend_a" ); + precacheshader( "waypoint_defend_b" ); + precacheshader( "waypoint_defuse" ); + precacheshader( "waypoint_defuse_a" ); + precacheshader( "waypoint_defuse_b" ); + precacheshader( "compass_waypoint_target" ); + precacheshader( "compass_waypoint_target_a" ); + precacheshader( "compass_waypoint_target_b" ); + precacheshader( "compass_waypoint_defend" ); + precacheshader( "compass_waypoint_defend_a" ); + precacheshader( "compass_waypoint_defend_b" ); + precacheshader( "compass_waypoint_defuse" ); + precacheshader( "compass_waypoint_defuse_a" ); + precacheshader( "compass_waypoint_defuse_b" ); + precachestring( &"MP_EXPLOSIVES_RECOVERED_BY" ); + precachestring( &"MP_EXPLOSIVES_DROPPED_BY" ); + precachestring( &"MP_EXPLOSIVES_PLANTED_BY" ); + precachestring( &"MP_EXPLOSIVES_DEFUSED_BY" ); + precachestring( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" ); + precachestring( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" ); + precachestring( &"MP_PLANTING_EXPLOSIVE" ); + precachestring( &"MP_DEFUSING_EXPLOSIVE" ); + precachestring( &"MP_TIME_EXTENDED" ); +} + +dem_getteamkillpenalty( einflictor, attacker, smeansofdeath, sweapon ) +{ + teamkill_penalty = maps/mp/gametypes/_globallogic_defaults::default_getteamkillpenalty( einflictor, attacker, smeansofdeath, sweapon ); + if ( isDefined( self.isdefusing ) || self.isdefusing && isDefined( self.isplanting ) && self.isplanting ) + { + teamkill_penalty *= level.teamkillpenaltymultiplier; + } + return teamkill_penalty; +} + +dem_getteamkillscore( einflictor, attacker, smeansofdeath, sweapon ) +{ + teamkill_score = maps/mp/gametypes/_rank::getscoreinfovalue( "team_kill" ); + if ( isDefined( self.isdefusing ) || self.isdefusing && isDefined( self.isplanting ) && self.isplanting ) + { + teamkill_score *= level.teamkillscoremultiplier; + } + return int( teamkill_score ); +} + +onroundswitch() +{ + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + if ( game[ "teamScores" ][ "allies" ] == ( level.scorelimit - 1 ) && game[ "teamScores" ][ "axis" ] == ( level.scorelimit - 1 ) ) + { + aheadteam = getbetterteam(); + if ( aheadteam != game[ "defenders" ] ) + { + game[ "switchedsides" ] = !game[ "switchedsides" ]; + } + level.halftimetype = "overtime"; + } + else + { + level.halftimetype = "halftime"; + game[ "switchedsides" ] = !game[ "switchedsides" ]; + } +} + +getbetterteam() +{ + kills[ "allies" ] = 0; + kills[ "axis" ] = 0; + deaths[ "allies" ] = 0; + deaths[ "axis" ] = 0; + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + team = player.pers[ "team" ]; + if ( isDefined( team ) || team == "allies" && team == "axis" ) + { + kills[ team ] += player.kills; + deaths[ team ] += player.deaths; + } + i++; + } + if ( kills[ "allies" ] > kills[ "axis" ] ) + { + return "allies"; + } + else + { + if ( kills[ "axis" ] > kills[ "allies" ] ) + { + return "axis"; + } + } + if ( deaths[ "allies" ] < deaths[ "axis" ] ) + { + return "allies"; + } + else + { + if ( deaths[ "axis" ] < deaths[ "allies" ] ) + { + return "axis"; + } + } + if ( randomint( 2 ) == 0 ) + { + return "allies"; + } + return "axis"; +} + +gamemodespawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.dem_enemy_base_influencer_score = set_dvar_float_if_unset( "scr_spawn_dem_enemy_base_influencer_score", "-500", reset_dvars ); + ss.dem_enemy_base_influencer_score_curve = set_dvar_if_unset( "scr_spawn_dem_enemy_base_influencer_score_curve", "constant", reset_dvars ); + ss.dem_enemy_base_influencer_radius = set_dvar_float_if_unset( "scr_spawn_dem_enemy_base_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); +} + +onstartgametype() +{ + setbombtimer( "A", 0 ); + setmatchflag( "bomb_timer_a", 0 ); + setbombtimer( "B", 0 ); + setmatchflag( "bomb_timer_b", 0 ); + level.usingextratime = 0; + level.spawnsystem.unifiedsideswitching = 0; + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + if ( game[ "switchedsides" ] ) + { + oldattackers = game[ "attackers" ]; + olddefenders = game[ "defenders" ]; + game[ "attackers" ] = olddefenders; + game[ "defenders" ] = oldattackers; + } + setclientnamemode( "manual_change" ); + game[ "strings" ][ "target_destroyed" ] = &"MP_TARGET_DESTROYED"; + game[ "strings" ][ "bomb_defused" ] = &"MP_BOMB_DEFUSED"; + precachestring( game[ "strings" ][ "target_destroyed" ] ); + precachestring( game[ "strings" ][ "bomb_defused" ] ); + level._effect[ "bombexplosion" ] = loadfx( "maps/mp_maps/fx_mp_exp_bomb" ); + if ( isDefined( game[ "overtime_round" ] ) ) + { + setobjectivetext( game[ "attackers" ], &"OBJECTIVES_DEM_ATTACKER" ); + setobjectivetext( game[ "defenders" ], &"OBJECTIVES_DEM_ATTACKER" ); + if ( level.splitscreen ) + { + setobjectivescoretext( game[ "attackers" ], &"OBJECTIVES_DEM_ATTACKER" ); + setobjectivescoretext( game[ "defenders" ], &"OBJECTIVES_DEM_ATTACKER" ); + } + else + { + setobjectivescoretext( game[ "attackers" ], &"OBJECTIVES_DEM_ATTACKER_SCORE" ); + setobjectivescoretext( game[ "defenders" ], &"OBJECTIVES_DEM_ATTACKER_SCORE" ); + } + setobjectivehinttext( game[ "attackers" ], &"OBJECTIVES_DEM_ATTACKER_HINT" ); + setobjectivehinttext( game[ "defenders" ], &"OBJECTIVES_DEM_ATTACKER_HINT" ); + } + else + { + setobjectivetext( game[ "attackers" ], &"OBJECTIVES_DEM_ATTACKER" ); + setobjectivetext( game[ "defenders" ], &"OBJECTIVES_SD_DEFENDER" ); + if ( level.splitscreen ) + { + setobjectivescoretext( game[ "attackers" ], &"OBJECTIVES_DEM_ATTACKER" ); + setobjectivescoretext( game[ "defenders" ], &"OBJECTIVES_SD_DEFENDER" ); + } + else + { + setobjectivescoretext( game[ "attackers" ], &"OBJECTIVES_DEM_ATTACKER_SCORE" ); + setobjectivescoretext( game[ "defenders" ], &"OBJECTIVES_SD_DEFENDER_SCORE" ); + } + setobjectivehinttext( game[ "attackers" ], &"OBJECTIVES_DEM_ATTACKER_HINT" ); + setobjectivehinttext( game[ "defenders" ], &"OBJECTIVES_SD_DEFENDER_HINT" ); + } + level.dembombzonename = "bombzone_dem"; + bombzones = getentarray( level.dembombzonename, "targetname" ); + if ( bombzones.size == 0 ) + { + level.dembombzonename = "bombzone"; + } + allowed[ 0 ] = "sd"; + allowed[ 1 ] = level.dembombzonename; + allowed[ 2 ] = "blocker"; + allowed[ 3 ] = "dem"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 1 ); + level.spawnmaxs = ( 0, 0, 1 ); + maps/mp/gametypes/_spawnlogic::dropspawnpoints( "mp_dem_spawn_attacker_a" ); + maps/mp/gametypes/_spawnlogic::dropspawnpoints( "mp_dem_spawn_attacker_b" ); + maps/mp/gametypes/_spawnlogic::dropspawnpoints( "mp_dem_spawn_defender_a" ); + maps/mp/gametypes/_spawnlogic::dropspawnpoints( "mp_dem_spawn_defender_b" ); + if ( !isDefined( game[ "overtime_round" ] ) ) + { + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_dem_spawn_defender_start" ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_dem_spawn_attacker_start" ); + } + else + { + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_dem_spawn_attackerOT_start" ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_dem_spawn_defenderOT_start" ); + } + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "attackers" ], "mp_dem_spawn_attacker" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "defenders" ], "mp_dem_spawn_defender" ); + if ( !isDefined( game[ "overtime_round" ] ) ) + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "defenders" ], "mp_dem_spawn_defender_a" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "defenders" ], "mp_dem_spawn_defender_b" ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.spawn_start = []; + if ( isDefined( game[ "overtime_round" ] ) ) + { + level.spawn_start[ "axis" ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_dem_spawn_attackerOT_start" ); + level.spawn_start[ "allies" ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_dem_spawn_defenderOT_start" ); + } + else + { + level.spawn_start[ "axis" ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_dem_spawn_defender_start" ); + level.spawn_start[ "allies" ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_dem_spawn_attacker_start" ); + } + thread updategametypedvars(); + thread bombs(); +} + +onspawnplayerunified() +{ + self.isplanting = 0; + self.isdefusing = 0; + self.isbombcarrier = 0; + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + if ( !predictedspawn ) + { + self.isplanting = 0; + self.isdefusing = 0; + self.isbombcarrier = 0; + if ( isDefined( self.carryicon ) ) + { + self.carryicon destroyelem(); + self.carryicon = undefined; + } + } + if ( !isDefined( game[ "overtime_round" ] ) ) + { + if ( self.pers[ "team" ] == game[ "attackers" ] ) + { + spawnpointname = "mp_dem_spawn_attacker_start"; + } + else + { + spawnpointname = "mp_dem_spawn_defender_start"; + } + } + else if ( isDefined( game[ "overtime_round" ] ) ) + { + if ( self.pers[ "team" ] == game[ "attackers" ] ) + { + spawnpointname = "mp_dem_spawn_attackerOT_start"; + } + else + { + spawnpointname = "mp_dem_spawn_defenderOT_start"; + } + } + spawnpoints = maps/mp/gametypes/_spawnlogic::getspawnpointarray( spawnpointname ); +/# + assert( spawnpoints.size ); +#/ + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_random( spawnpoints ); + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "dem" ); + } +} + +dem_playerspawnedcb() +{ + level notify( "spawned_player" ); +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + thread checkallowspectating(); + bombzone = undefined; + index = 0; + while ( index < level.bombzones.size ) + { + if ( !isDefined( level.bombzones[ index ].bombexploded ) || !level.bombzones[ index ].bombexploded ) + { + dist = distance2d( self.origin, level.bombzones[ index ].curorigin ); + if ( dist < level.defaultoffenseradius ) + { + bombzone = level.bombzones[ index ]; + break; + } + else dist = distance2d( attacker.origin, level.bombzones[ index ].curorigin ); + if ( dist < level.defaultoffenseradius ) + { + inbombzone = 1; + break; + } + } + else + { + index++; + } + } + if ( isDefined( bombzone ) && isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + if ( bombzone maps/mp/gametypes/_gameobjects::getownerteam() != attacker.team ) + { + if ( !isDefined( attacker.dem_offends ) ) + { + attacker.dem_offends = 0; + } + attacker.dem_offends++; + if ( level.playeroffensivemax >= attacker.dem_offends ) + { + attacker maps/mp/_medals::offenseglobalcount(); + attacker addplayerstatwithgametype( "OFFENDS", 1 ); + self recordkillmodifier( "defending" ); + maps/mp/_scoreevents::processscoreevent( "killed_defender", attacker, self, sweapon ); + } + else + { +/# + attacker iprintlnbold( "GAMETYPE DEBUG: NOT GIVING YOU OFFENSIVE CREDIT AS BOOSTING PREVENTION" ); +#/ + } + } + else if ( !isDefined( attacker.dem_defends ) ) + { + attacker.dem_defends = 0; + } + attacker.dem_defends++; + if ( level.playerdefensivemax >= attacker.dem_defends ) + { + if ( isDefined( attacker.pers[ "defends" ] ) ) + { + attacker.pers[ "defends" ]++; + attacker.defends = attacker.pers[ "defends" ]; + } + attacker maps/mp/_medals::defenseglobalcount(); + attacker addplayerstatwithgametype( "DEFENDS", 1 ); + self recordkillmodifier( "assaulting" ); + maps/mp/_scoreevents::processscoreevent( "killed_attacker", attacker, self, sweapon ); + } + else + { +/# + attacker iprintlnbold( "GAMETYPE DEBUG: NOT GIVING YOU DEFENSIVE CREDIT AS BOOSTING PREVENTION" ); +#/ + } + } + if ( self.isplanting == 1 ) + { + self recordkillmodifier( "planting" ); + } + if ( self.isdefusing == 1 ) + { + self recordkillmodifier( "defusing" ); + } +} + +checkallowspectating() +{ + self endon( "disconnect" ); + wait 0,05; + update = 0; + if ( level.numliveslivesleft = self.pers[ "lives" ]; + && !level.alivecount[ game[ "attackers" ] ] && !livesleft ) + { + level.spectateoverride[ game[ "attackers" ] ].allowenemyspectate = 1; + update = 1; + } + if ( !level.alivecount[ game[ "defenders" ] ] && !livesleft ) + { + level.spectateoverride[ game[ "defenders" ] ].allowenemyspectate = 1; + update = 1; + } + if ( update ) + { + maps/mp/gametypes/_spectating::updatespectatesettings(); + } +} + +dem_endgame( winningteam, endreasontext ) +{ + if ( isDefined( winningteam ) && winningteam != "tie" ) + { + maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( winningteam, 1 ); + } + thread maps/mp/gametypes/_globallogic::endgame( winningteam, endreasontext ); +} + +ondeadevent( team ) +{ + if ( level.bombexploded || level.bombdefused ) + { + return; + } + if ( team == "all" ) + { + if ( level.bombplanted ) + { + dem_endgame( game[ "attackers" ], game[ "strings" ][ game[ "defenders" ] + "_eliminated" ] ); + } + else + { + dem_endgame( game[ "defenders" ], game[ "strings" ][ game[ "attackers" ] + "_eliminated" ] ); + } + } + else if ( team == game[ "attackers" ] ) + { + if ( level.bombplanted ) + { + return; + } + dem_endgame( game[ "defenders" ], game[ "strings" ][ game[ "attackers" ] + "_eliminated" ] ); + } + else + { + if ( team == game[ "defenders" ] ) + { + dem_endgame( game[ "attackers" ], game[ "strings" ][ game[ "defenders" ] + "_eliminated" ] ); + } + } +} + +ononeleftevent( team ) +{ + if ( level.bombexploded || level.bombdefused ) + { + return; + } + warnlastplayer( team ); +} + +ontimelimit() +{ + if ( isDefined( game[ "overtime_round" ] ) ) + { + dem_endgame( "tie", game[ "strings" ][ "time_limit_reached" ] ); + } + else if ( level.teambased ) + { + bombzonesleft = 0; + index = 0; + while ( index < level.bombzones.size ) + { + if ( !isDefined( level.bombzones[ index ].bombexploded ) || !level.bombzones[ index ].bombexploded ) + { + bombzonesleft++; + } + index++; + } + if ( bombzonesleft == 0 ) + { + dem_endgame( game[ "attackers" ], game[ "strings" ][ "target_destroyed" ] ); + } + else + { + dem_endgame( game[ "defenders" ], game[ "strings" ][ "time_limit_reached" ] ); + } + } + else + { + dem_endgame( "tie", game[ "strings" ][ "time_limit_reached" ] ); + } +} + +warnlastplayer( team ) +{ + if ( !isDefined( level.warnedlastplayer ) ) + { + level.warnedlastplayer = []; + } + if ( isDefined( level.warnedlastplayer[ team ] ) ) + { + return; + } + level.warnedlastplayer[ team ] = 1; + players = level.players; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team && isDefined( player.pers[ "class" ] ) ) + { + if ( player.sessionstate == "playing" && !player.afk ) + { + break; + } + } + else + { + i++; + } + } + if ( i == players.size ) + { + return; + } + players[ i ] thread givelastattackerwarning(); +} + +givelastattackerwarning() +{ + self endon( "death" ); + self endon( "disconnect" ); + fullhealthtime = 0; + interval = 0,05; + while ( 1 ) + { + if ( self.health != self.maxhealth ) + { + fullhealthtime = 0; + } + else + { + fullhealthtime += interval; + } + wait interval; + if ( self.health == self.maxhealth && fullhealthtime >= 3 ) + { + break; + } + else + { + } + } + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "sudden_death" ); +} + +updategametypedvars() +{ + level.planttime = getgametypesetting( "plantTime" ); + level.defusetime = getgametypesetting( "defuseTime" ); + level.bombtimer = getgametypesetting( "bombTimer" ); + level.extratime = getgametypesetting( "extraTime" ); + level.overtimetimelimit = getgametypesetting( "OvertimetimeLimit" ); + level.teamkillpenaltymultiplier = getgametypesetting( "teamKillPenalty" ); + level.teamkillscoremultiplier = getgametypesetting( "teamKillScore" ); + level.playereventslpm = getgametypesetting( "maxPlayerEventsPerMinute" ); + level.bombeventslpm = getgametypesetting( "maxObjectiveEventsPerMinute" ); + level.playeroffensivemax = getgametypesetting( "maxPlayerOffensive" ); + level.playerdefensivemax = getgametypesetting( "maxPlayerDefensive" ); +} + +resetbombzone() +{ + if ( isDefined( game[ "overtime_round" ] ) ) + { + self maps/mp/gametypes/_gameobjects::setownerteam( "neutral" ); + self maps/mp/gametypes/_gameobjects::allowuse( "any" ); + } + else + { + self maps/mp/gametypes/_gameobjects::allowuse( "enemy" ); + } + self maps/mp/gametypes/_gameobjects::setusetime( level.planttime ); + self maps/mp/gametypes/_gameobjects::setusetext( &"MP_PLANTING_EXPLOSIVE" ); + self maps/mp/gametypes/_gameobjects::setusehinttext( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" ); + self maps/mp/gametypes/_gameobjects::setkeyobject( level.ddbomb ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", "waypoint_defend" + self.label ); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_defend" + self.label ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", "waypoint_target" + self.label ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", "waypoint_target" + self.label ); + self maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + self.useweapon = "briefcase_bomb_mp"; +} + +setupfordefusing() +{ + self maps/mp/gametypes/_gameobjects::allowuse( "friendly" ); + self maps/mp/gametypes/_gameobjects::setusetime( level.defusetime ); + self maps/mp/gametypes/_gameobjects::setusetext( &"MP_DEFUSING_EXPLOSIVE" ); + self maps/mp/gametypes/_gameobjects::setusehinttext( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" ); + self maps/mp/gametypes/_gameobjects::setkeyobject( undefined ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", "compass_waypoint_defuse" + self.label ); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_defuse" + self.label ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", "compass_waypoint_defend" + self.label ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", "waypoint_defend" + self.label ); + self maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); +} + +bombs() +{ + level.bombaplanted = 0; + level.bombbplanted = 0; + level.bombplanted = 0; + level.bombdefused = 0; + level.bombexploded = 0; + sdbomb = getent( "sd_bomb", "targetname" ); + if ( isDefined( sdbomb ) ) + { + sdbomb delete(); + } + precachemodel( "t5_weapon_briefcase_bomb_world" ); + level.bombzones = []; + bombzones = getentarray( level.dembombzonename, "targetname" ); + index = 0; + while ( index < bombzones.size ) + { + trigger = bombzones[ index ]; + scriptlabel = trigger.script_label; + visuals = getentarray( bombzones[ index ].target, "targetname" ); + clipbrushes = getentarray( "bombzone_clip" + scriptlabel, "targetname" ); + defusetrig = getent( visuals[ 0 ].target, "targetname" ); + bombsiteteamowner = game[ "defenders" ]; + bombsiteallowuse = "enemy"; + if ( isDefined( game[ "overtime_round" ] ) ) + { + if ( scriptlabel != "_overtime" ) + { + trigger delete(); + defusetrig delete(); + visuals[ 0 ] delete(); + _a831 = clipbrushes; + _k831 = getFirstArrayKey( _a831 ); + while ( isDefined( _k831 ) ) + { + clip = _a831[ _k831 ]; + clip delete(); + _k831 = getNextArrayKey( _a831, _k831 ); + } + } + else bombsiteteamowner = "neutral"; + bombsiteallowuse = "any"; + scriptlabel = "_a"; + } + else + { + if ( scriptlabel == "_overtime" ) + { + trigger delete(); + defusetrig delete(); + visuals[ 0 ] delete(); + _a846 = clipbrushes; + _k846 = getFirstArrayKey( _a846 ); + while ( isDefined( _k846 ) ) + { + clip = _a846[ _k846 ]; + clip delete(); + _k846 = getNextArrayKey( _a846, _k846 ); + } + } + } + else name = istring( scriptlabel ); + precachestring( name ); + bombzone = maps/mp/gametypes/_gameobjects::createuseobject( bombsiteteamowner, trigger, visuals, ( 0, 0, 1 ), name ); + bombzone maps/mp/gametypes/_gameobjects::allowuse( bombsiteallowuse ); + bombzone maps/mp/gametypes/_gameobjects::setusetime( level.planttime ); + bombzone maps/mp/gametypes/_gameobjects::setusetext( &"MP_PLANTING_EXPLOSIVE" ); + bombzone maps/mp/gametypes/_gameobjects::setusehinttext( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" ); + bombzone maps/mp/gametypes/_gameobjects::setkeyobject( level.ddbomb ); + bombzone.label = scriptlabel; + bombzone.index = index; + bombzone maps/mp/gametypes/_gameobjects::set2dicon( "friendly", "compass_waypoint_defend" + scriptlabel ); + bombzone maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_defend" + scriptlabel ); + bombzone maps/mp/gametypes/_gameobjects::set2dicon( "enemy", "compass_waypoint_target" + scriptlabel ); + bombzone maps/mp/gametypes/_gameobjects::set3dicon( "enemy", "waypoint_target" + scriptlabel ); + bombzone maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + bombzone.onbeginuse = ::onbeginuse; + bombzone.onenduse = ::onenduse; + bombzone.onuse = ::onuseobject; + bombzone.oncantuse = ::oncantuse; + bombzone.useweapon = "briefcase_bomb_mp"; + bombzone.visuals[ 0 ].killcament = spawn( "script_model", bombzone.visuals[ 0 ].origin + vectorScale( ( 0, 0, 1 ), 128 ) ); + i = 0; + while ( i < visuals.size ) + { + if ( isDefined( visuals[ i ].script_exploder ) ) + { + bombzone.exploderindex = visuals[ i ].script_exploder; + break; + } + else + { + i++; + } + } + level.bombzones[ level.bombzones.size ] = bombzone; + bombzone.bombdefusetrig = defusetrig; +/# + assert( isDefined( bombzone.bombdefusetrig ) ); +#/ + bombzone.bombdefusetrig.origin += vectorScale( ( 0, 0, 1 ), 10000 ); + bombzone.bombdefusetrig.label = scriptlabel; + dem_enemy_base_influencer_score = level.spawnsystem.dem_enemy_base_influencer_score; + dem_enemy_base_influencer_score_curve = level.spawnsystem.dem_enemy_base_influencer_score_curve; + dem_enemy_base_influencer_radius = level.spawnsystem.dem_enemy_base_influencer_radius; + team_mask = getteammask( game[ "attackers" ] ); + bombzone.spawninfluencer = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, trigger.origin, dem_enemy_base_influencer_radius, dem_enemy_base_influencer_score, team_mask, "dem_enemy_base,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( dem_enemy_base_influencer_score_curve ) ); + index++; + } + index = 0; + while ( index < level.bombzones.size ) + { + array = []; + otherindex = 0; + while ( otherindex < level.bombzones.size ) + { + if ( otherindex != index ) + { + array[ array.size ] = level.bombzones[ otherindex ]; + } + otherindex++; + } + level.bombzones[ index ].otherbombzones = array; + index++; + } +} + +onbeginuse( player ) +{ + timeremaining = maps/mp/gametypes/_globallogic_utils::gettimeremaining(); + if ( timeremaining <= ( level.planttime * 1000 ) ) + { + maps/mp/gametypes/_globallogic_utils::pausetimer(); + level.haspausedtimer = 1; + } + if ( self maps/mp/gametypes/_gameobjects::isfriendlyteam( player.pers[ "team" ] ) ) + { + player playsound( "mpl_sd_bomb_defuse" ); + player.isdefusing = 1; + player thread maps/mp/gametypes/_battlechatter_mp::gametypespecificbattlechatter( "sd_enemyplant", player.pers[ "team" ] ); + bestdistance = 9000000; + closestbomb = undefined; + if ( isDefined( level.ddbombmodel ) ) + { + keys = getarraykeys( level.ddbombmodel ); + bomblabel = 0; + while ( bomblabel < keys.size ) + { + bomb = level.ddbombmodel[ keys[ bomblabel ] ]; + if ( !isDefined( bomb ) ) + { + bomblabel++; + continue; + } + else + { + dist = distancesquared( player.origin, bomb.origin ); + if ( dist < bestdistance ) + { + bestdistance = dist; + closestbomb = bomb; + } + } + bomblabel++; + } +/# + assert( isDefined( closestbomb ) ); +#/ + player.defusing = closestbomb; + closestbomb hide(); + } + } + else + { + player.isplanting = 1; + player thread maps/mp/gametypes/_battlechatter_mp::gametypespecificbattlechatter( "sd_friendlyplant", player.pers[ "team" ] ); + } + player playsound( "fly_bomb_raise_plr" ); +} + +onenduse( team, player, result ) +{ + if ( !isDefined( player ) ) + { + return; + } + if ( !level.bombaplanted && !level.bombbplanted ) + { + maps/mp/gametypes/_globallogic_utils::resumetimer(); + level.haspausedtimer = 0; + } + player.isdefusing = 0; + player.isplanting = 0; + player notify( "event_ended" ); + if ( self maps/mp/gametypes/_gameobjects::isfriendlyteam( player.pers[ "team" ] ) ) + { + if ( isDefined( player.defusing ) && !result ) + { + player.defusing show(); + } + } +} + +oncantuse( player ) +{ + player iprintlnbold( &"MP_CANT_PLANT_WITHOUT_BOMB" ); +} + +onuseobject( player ) +{ + team = player.team; + enemyteam = getotherteam( team ); + self updateeventsperminute(); + player updateeventsperminute(); + if ( !self maps/mp/gametypes/_gameobjects::isfriendlyteam( team ) ) + { + self maps/mp/gametypes/_gameobjects::setflags( 1 ); + level thread bombplanted( self, player ); + player logstring( "bomb planted: " + self.label ); + bbprint( "mpobjective", "gametime %d objtype %s label %s team %s", getTime(), "dem_bombplant", self.label, team ); + player notify( "bomb_planted" ); + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "DEM_WE_PLANT", team, 0, 0, 5 ); + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "DEM_THEY_PLANT", enemyteam, 0, 0, 5 ); + if ( isDefined( player.pers[ "plants" ] ) ) + { + player.pers[ "plants" ]++; + player.plants = player.pers[ "plants" ]; + } + if ( !isscoreboosting( player, self ) ) + { + maps/mp/_demo::bookmark( "event", getTime(), player ); + player addplayerstatwithgametype( "PLANTS", 1 ); + maps/mp/_scoreevents::processscoreevent( "planted_bomb", player ); + player recordgameevent( "plant" ); + } + else + { +/# + player iprintlnbold( "GAMETYPE DEBUG: NOT GIVING YOU PLANT CREDIT AS BOOSTING PREVENTION" ); +#/ + } + level thread maps/mp/_popups::displayteammessagetoall( &"MP_EXPLOSIVES_PLANTED_BY", player ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "bomb_planted" ); + } + else + { + self maps/mp/gametypes/_gameobjects::setflags( 0 ); + player notify( "bomb_defused" ); + player logstring( "bomb defused: " + self.label ); + self thread bombdefused(); + self resetbombzone(); + bbprint( "mpobjective", "gametime %d objtype %s label %s team %s", getTime(), "dem_bombdefused", self.label, team ); + if ( isDefined( player.pers[ "defuses" ] ) ) + { + player.pers[ "defuses" ]++; + player.defuses = player.pers[ "defuses" ]; + } + if ( !isscoreboosting( player, self ) ) + { + maps/mp/_demo::bookmark( "event", getTime(), player ); + player addplayerstatwithgametype( "DEFUSES", 1 ); + maps/mp/_scoreevents::processscoreevent( "defused_bomb", player ); + player recordgameevent( "defuse" ); + } + else + { +/# + player iprintlnbold( "GAMETYPE DEBUG: NOT GIVING YOU DEFUSE CREDIT AS BOOSTING PREVENTION" ); +#/ + } + level thread maps/mp/_popups::displayteammessagetoall( &"MP_EXPLOSIVES_DEFUSED_BY", player ); + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "DEM_WE_DEFUSE", team, 0, 0, 5 ); + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "DEM_THEY_DEFUSE", enemyteam, 0, 0, 5 ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "bomb_defused" ); + } +} + +ondrop( player ) +{ + if ( !level.bombplanted ) + { + if ( isDefined( player ) ) + { + player logstring( "bomb dropped" ); + } + else + { + logstring( "bomb dropped" ); + } + } + player notify( "event_ended" ); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_bomb" ); + maps/mp/_utility::playsoundonplayers( game[ "bomb_dropped_sound" ], game[ "attackers" ] ); +} + +onpickup( player ) +{ + player.isbombcarrier = 1; + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_defend" ); + if ( !level.bombdefused ) + { + thread playsoundonplayers( "mus_sd_pickup" + "_" + level.teampostfix[ player.pers[ "team" ] ], player.pers[ "team" ] ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "bomb_taken", player.pers[ "team" ] ); + player logstring( "bomb taken" ); + } + maps/mp/_utility::playsoundonplayers( game[ "bomb_recovered_sound" ], game[ "attackers" ] ); +} + +onreset() +{ +} + +bombreset( label, reason ) +{ + if ( label == "_a" ) + { + level.bombaplanted = 0; + setbombtimer( "A", 0 ); + } + else + { + level.bombbplanted = 0; + setbombtimer( "B", 0 ); + } + setmatchflag( "bomb_timer" + label, 0 ); + if ( !level.bombaplanted && !level.bombbplanted ) + { + maps/mp/gametypes/_globallogic_utils::resumetimer(); + } + self.visuals[ 0 ] maps/mp/gametypes/_globallogic_utils::stoptickingsound(); +} + +dropbombmodel( player, site ) +{ + trace = bullettrace( player.origin + vectorScale( ( 0, 0, 1 ), 20 ), player.origin - vectorScale( ( 0, 0, 1 ), 2000 ), 0, player ); + tempangle = randomfloat( 360 ); + forward = ( cos( tempangle ), sin( tempangle ), 0 ); + forward = vectornormalize( forward - vectorScale( trace[ "normal" ], vectordot( forward, trace[ "normal" ] ) ) ); + dropangles = vectorToAngle( forward ); + if ( isDefined( trace[ "surfacetype" ] ) && trace[ "surfacetype" ] == "water" ) + { + phystrace = playerphysicstrace( player.origin + vectorScale( ( 0, 0, 1 ), 20 ), player.origin - vectorScale( ( 0, 0, 1 ), 2000 ) ); + if ( isDefined( phystrace ) ) + { + trace[ "position" ] = phystrace; + } + } + level.ddbombmodel[ site ] = spawn( "script_model", trace[ "position" ] ); + level.ddbombmodel[ site ].angles = dropangles; + level.ddbombmodel[ site ] setmodel( "prop_suitcase_bomb" ); +} + +bombplanted( destroyedobj, player ) +{ + level endon( "game_ended" ); + destroyedobj endon( "bomb_defused" ); + team = player.team; + game[ "challenge" ][ team ][ "plantedBomb" ] = 1; + maps/mp/gametypes/_globallogic_utils::pausetimer(); + destroyedobj.bombplanted = 1; + destroyedobj.visuals[ 0 ] thread maps/mp/gametypes/_globallogic_utils::playtickingsound( "mpl_sab_ui_suitcasebomb_timer" ); + destroyedobj.tickingobject = destroyedobj.visuals[ 0 ]; + label = destroyedobj.label; + detonatetime = int( getTime() + ( level.bombtimer * 1000 ) ); + updatebombtimers( label, detonatetime ); + destroyedobj.detonatetime = detonatetime; + trace = bullettrace( player.origin + vectorScale( ( 0, 0, 1 ), 20 ), player.origin - vectorScale( ( 0, 0, 1 ), 2000 ), 0, player ); + tempangle = randomfloat( 360 ); + forward = ( cos( tempangle ), sin( tempangle ), 0 ); + forward = vectornormalize( forward - vectorScale( trace[ "normal" ], vectordot( forward, trace[ "normal" ] ) ) ); + dropangles = vectorToAngle( forward ); + self dropbombmodel( player, destroyedobj.label ); + destroyedobj maps/mp/gametypes/_gameobjects::allowuse( "none" ); + destroyedobj maps/mp/gametypes/_gameobjects::setvisibleteam( "none" ); + if ( isDefined( game[ "overtime_round" ] ) ) + { + destroyedobj maps/mp/gametypes/_gameobjects::setownerteam( getotherteam( player.team ) ); + } + destroyedobj setupfordefusing(); + player.isbombcarrier = 0; + game[ "challenge" ][ team ][ "plantedBomb" ] = 1; + destroyedobj waitlongdurationwithbombtimeupdate( label, level.bombtimer ); + destroyedobj bombreset( label, "bomb_exploded" ); + if ( level.gameended ) + { + return; + } + bbprint( "mpobjective", "gametime %d objtype %s label %s team %s", getTime(), "dem_bombexplode", label, team ); + destroyedobj.bombexploded = 1; + game[ "challenge" ][ team ][ "destroyedBombSite" ] = 1; + explosionorigin = destroyedobj.curorigin; + level.ddbombmodel[ destroyedobj.label ] delete(); + if ( isDefined( player ) ) + { + destroyedobj.visuals[ 0 ] radiusdamage( explosionorigin, 512, 200, 20, player, "MOD_EXPLOSIVE", "briefcase_bomb_mp" ); + player addplayerstatwithgametype( "DESTRUCTIONS", 1 ); + level thread maps/mp/_popups::displayteammessagetoall( &"MP_EXPLOSIVES_BLOWUP_BY", player ); + maps/mp/_scoreevents::processscoreevent( "bomb_detonated", player ); + player recordgameevent( "destroy" ); + } + else + { + destroyedobj.visuals[ 0 ] radiusdamage( explosionorigin, 512, 200, 20, undefined, "MOD_EXPLOSIVE", "briefcase_bomb_mp" ); + } + currenttime = getTime(); + while ( isDefined( level.lastbombexplodetime ) && level.lastbombexplodebyteam == player.team ) + { + while ( ( level.lastbombexplodetime + 10000 ) > currenttime ) + { + i = 0; + while ( i < level.players.size ) + { + if ( level.players[ i ].team == player.team ) + { + level.players[ i ] maps/mp/_challenges::bothbombsdetonatewithintime(); + } + i++; + } + } + } + level.lastbombexplodetime = currenttime; + level.lastbombexplodebyteam = player.team; + rot = randomfloat( 360 ); + explosioneffect = spawnfx( level._effect[ "bombexplosion" ], explosionorigin + vectorScale( ( 0, 0, 1 ), 50 ), ( 0, 0, 1 ), ( cos( rot ), sin( rot ), 0 ) ); + triggerfx( explosioneffect ); + thread playsoundinspace( "mpl_sd_exp_suitcase_bomb_main", explosionorigin ); + if ( isDefined( destroyedobj.exploderindex ) ) + { + exploder( destroyedobj.exploderindex ); + } + bombzonesleft = 0; + index = 0; + while ( index < level.bombzones.size ) + { + if ( !isDefined( level.bombzones[ index ].bombexploded ) || !level.bombzones[ index ].bombexploded ) + { + bombzonesleft++; + } + index++; + } + destroyedobj maps/mp/gametypes/_gameobjects::disableobject(); + if ( bombzonesleft == 0 ) + { + maps/mp/gametypes/_globallogic_utils::pausetimer(); + level.haspausedtimer = 1; + setgameendtime( 0 ); + wait 3; + dem_endgame( team, game[ "strings" ][ "target_destroyed" ] ); + } + else + { + enemyteam = getotherteam( team ); + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "DEM_WE_SCORE", team, 0, 0, 5 ); + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "DEM_THEY_SCORE", enemyteam, 0, 0, 5 ); + if ( [[ level.gettimelimit ]]() > 0 ) + { + level.usingextratime = 1; + } + removeinfluencer( destroyedobj.spawninfluencer ); + destroyedobj.spawninfluencer = undefined; + maps/mp/gametypes/_spawnlogic::clearspawnpoints(); + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "attackers" ], "mp_dem_spawn_attacker" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "defenders" ], "mp_dem_spawn_defender" ); + if ( label == "_a" ) + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "attackers" ], "mp_dem_spawn_attacker_a" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "defenders" ], "mp_dem_spawn_defender_b" ); + } + else + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "attackers" ], "mp_dem_spawn_attacker_b" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( game[ "defenders" ], "mp_dem_spawn_defender_a" ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + } +} + +gettimelimit() +{ + timelimit = maps/mp/gametypes/_globallogic_defaults::default_gettimelimit(); + if ( isDefined( game[ "overtime_round" ] ) ) + { + timelimit = level.overtimetimelimit; + } + if ( level.usingextratime ) + { + return timelimit + level.extratime; + } + return timelimit; +} + +shouldplayovertimeround() +{ + if ( isDefined( game[ "overtime_round" ] ) ) + { + return 0; + } + if ( game[ "teamScores" ][ "allies" ] == ( level.scorelimit - 1 ) && game[ "teamScores" ][ "axis" ] == ( level.scorelimit - 1 ) ) + { + return 1; + } + return 0; +} + +waitlongdurationwithbombtimeupdate( whichbomb, duration ) +{ + if ( duration == 0 ) + { + return; + } +/# + assert( duration > 0 ); +#/ + starttime = getTime(); + endtime = getTime() + ( duration * 1000 ); + while ( getTime() < endtime ) + { + maps/mp/gametypes/_hostmigration::waittillhostmigrationstarts( ( endtime - getTime() ) / 1000 ); + while ( isDefined( level.hostmigrationtimer ) ) + { + endtime += 250; + updatebombtimers( whichbomb, endtime ); + wait 0,25; + } + } +/# + if ( getTime() != endtime ) + { + println( "SCRIPT WARNING: gettime() = " + getTime() + " NOT EQUAL TO endtime = " + endtime ); +#/ + } + while ( isDefined( level.hostmigrationtimer ) ) + { + endtime += 250; + updatebombtimers( whichbomb, endtime ); + wait 0,25; + } + return getTime() - starttime; +} + +updatebombtimers( whichbomb, detonatetime ) +{ + if ( whichbomb == "_a" ) + { + level.bombaplanted = 1; + setbombtimer( "A", int( detonatetime ) ); + } + else + { + level.bombbplanted = 1; + setbombtimer( "B", int( detonatetime ) ); + } + setmatchflag( "bomb_timer" + whichbomb, int( detonatetime ) ); +} + +bombdefused() +{ + self.tickingobject maps/mp/gametypes/_globallogic_utils::stoptickingsound(); + self maps/mp/gametypes/_gameobjects::allowuse( "none" ); + self maps/mp/gametypes/_gameobjects::setvisibleteam( "none" ); + self.bombdefused = 1; + self notify( "bomb_defused" ); + self.bombplanted = 0; + self bombreset( self.label, "bomb_defused" ); +} + +play_one_left_underscore( team, enemyteam ) +{ + wait 3; + if ( !isDefined( team ) || !isDefined( enemyteam ) ) + { + return; + } + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "DEM_ONE_LEFT_UNDERSCORE", team, 0, 0 ); + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "DEM_ONE_LEFT_UNDERSCORE", enemyteam, 0, 0 ); +} + +updateeventsperminute() +{ + if ( !isDefined( self.eventsperminute ) ) + { + self.numbombevents = 0; + self.eventsperminute = 0; + } + self.numbombevents++; + minutespassed = maps/mp/gametypes/_globallogic_utils::gettimepassed() / 60000; + if ( isplayer( self ) && isDefined( self.timeplayed[ "total" ] ) ) + { + minutespassed = self.timeplayed[ "total" ] / 60; + } + self.eventsperminute = self.numbombevents / minutespassed; + if ( self.eventsperminute > self.numbombevents ) + { + self.eventsperminute = self.numbombevents; + } +} + +isscoreboosting( player, flag ) +{ + if ( !level.rankedmatch ) + { + return 0; + } + if ( player.eventsperminute > level.playereventslpm ) + { + return 1; + } + if ( flag.eventsperminute > level.bombeventslpm ) + { + return 1; + } + return 0; +} diff --git a/patch_mp/maps/mp/gametypes/dm.gsc b/patch_mp/maps/mp/gametypes/dm.gsc new file mode 100644 index 0000000..e03e910 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/dm.gsc @@ -0,0 +1,133 @@ +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +main() +{ + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 50000 ); + registerroundlimit( 0, 10 ); + registerroundwinlimit( 0, 10 ); + registernumlives( 0, 100 ); + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 0, 0, 1440 ); + level.scoreroundbased = getgametypesetting( "roundscorecarry" ) == 0; + level.teamscoreperkill = getgametypesetting( "teamScorePerKill" ); + level.teamscoreperdeath = getgametypesetting( "teamScorePerDeath" ); + level.teamscoreperheadshot = getgametypesetting( "teamScorePerHeadshot" ); + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onplayerkilled = ::onplayerkilled; + game[ "dialog" ][ "gametype" ] = "ffa_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "hcffa_start"; + game[ "dialog" ][ "offense_obj" ] = "generic_boost"; + game[ "dialog" ][ "defense_obj" ] = "generic_boost"; + setscoreboardcolumns( "pointstowin", "kills", "deaths", "headshots", "score" ); +} + +onstartgametype() +{ + setclientnamemode( "auto_change" ); + setobjectivetext( "allies", &"OBJECTIVES_DM" ); + setobjectivetext( "axis", &"OBJECTIVES_DM" ); + if ( level.splitscreen ) + { + setobjectivescoretext( "allies", &"OBJECTIVES_DM" ); + setobjectivescoretext( "axis", &"OBJECTIVES_DM" ); + } + else + { + setobjectivescoretext( "allies", &"OBJECTIVES_DM_SCORE" ); + setobjectivescoretext( "axis", &"OBJECTIVES_DM_SCORE" ); + } + setobjectivehinttext( "allies", &"OBJECTIVES_DM_HINT" ); + setobjectivehinttext( "axis", &"OBJECTIVES_DM_HINT" ); + allowed[ 0 ] = "dm"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 0 ); + level.spawnmaxs = ( 0, 0, 0 ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_dm_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_dm_spawn" ); + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.usestartspawns = 0; + level.displayroundendtext = 0; + level thread onscoreclosemusic(); + if ( !isoneround() ) + { + level.displayroundendtext = 1; + } +} + +onspawnplayerunified() +{ + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( self.pers[ "team" ] ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_dm( spawnpoints ); + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "dm" ); + } +} + +onendgame( winningplayer ) +{ + if ( isDefined( winningplayer ) && isplayer( winningplayer ) ) + { + [[ level._setplayerscore ]]( winningplayer, winningplayer [[ level._getplayerscore ]]() + 1 ); + } +} + +onscoreclosemusic() +{ + while ( !level.gameended ) + { + scorelimit = level.scorelimit; + scorethreshold = scorelimit * 0,9; + i = 0; + while ( i < level.players.size ) + { + scorecheck = [[ level._getplayerscore ]]( level.players[ i ] ); + if ( scorecheck >= scorethreshold ) + { + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "TIME_OUT", "both" ); + thread maps/mp/gametypes/_globallogic_audio::actionmusicset(); + return; + } + i++; + } + wait 0,5; + } +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( !isplayer( attacker ) || self == attacker ) + { + return; + } + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.teamscoreperkill ); + self maps/mp/gametypes/_globallogic_score::givepointstowin( level.teamscoreperdeath * -1 ); + if ( smeansofdeath == "MOD_HEAD_SHOT" ) + { + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.teamscoreperheadshot ); + } +} diff --git a/patch_mp/maps/mp/gametypes/dom.gsc b/patch_mp/maps/mp/gametypes/dom.gsc new file mode 100644 index 0000000..af7ac07 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/dom.gsc @@ -0,0 +1,1539 @@ +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/_popups; +#include maps/mp/_demo; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/teams/_teams; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + if ( getDvar( "mapname" ) == "mp_background" ) + { + return; + } + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 1000 ); + registerroundlimit( 0, 10 ); + registerroundwinlimit( 0, 10 ); + registerroundswitch( 0, 9 ); + registernumlives( 0, 100 ); + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + level.scoreroundbased = getgametypesetting( "roundscorecarry" ) == 0; + level.teambased = 1; + level.overrideteamscore = 1; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onplayerkilled = ::onplayerkilled; + level.onroundswitch = ::onroundswitch; + level.onprecachegametype = ::onprecachegametype; + level.onendgame = ::onendgame; + level.gamemodespawndvars = ::dom_gamemodespawndvars; + level.onroundendgame = ::onroundendgame; + game[ "dialog" ][ "gametype" ] = "dom_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "hcdom_start"; + game[ "dialog" ][ "offense_obj" ] = "cap_start"; + game[ "dialog" ][ "defense_obj" ] = "cap_start"; + level.lastdialogtime = 0; + if ( !sessionmodeissystemlink() && !sessionmodeisonlinegame() && issplitscreen() ) + { + setscoreboardcolumns( "score", "kills", "captures", "defends", "deaths" ); + } + else + { + setscoreboardcolumns( "score", "kills", "deaths", "captures", "defends" ); + } + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "gamemode_objective", 0 ); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "gamemode_objective_a", 0 ); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "gamemode_objective_b", 0 ); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "gamemode_objective_c", 0 ); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "gamemode_changing_a", 0 ); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "gamemode_changing_b", 0 ); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "gamemode_changing_c", 0 ); +} + +onprecachegametype() +{ +} + +onstartgametype() +{ + setobjectivetext( "allies", &"OBJECTIVES_DOM" ); + setobjectivetext( "axis", &"OBJECTIVES_DOM" ); + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + if ( game[ "switchedsides" ] ) + { + oldattackers = game[ "attackers" ]; + olddefenders = game[ "defenders" ]; + game[ "attackers" ] = olddefenders; + game[ "defenders" ] = oldattackers; + } + if ( level.splitscreen ) + { + setobjectivescoretext( "allies", &"OBJECTIVES_DOM" ); + setobjectivescoretext( "axis", &"OBJECTIVES_DOM" ); + } + else + { + setobjectivescoretext( "allies", &"OBJECTIVES_DOM_SCORE" ); + setobjectivescoretext( "axis", &"OBJECTIVES_DOM_SCORE" ); + } + setobjectivehinttext( "allies", &"OBJECTIVES_DOM_HINT" ); + setobjectivehinttext( "axis", &"OBJECTIVES_DOM_HINT" ); + level.flagbasefxid = []; + level.flagbasefxid[ "allies" ] = loadfx( "misc/fx_ui_flagbase_" + game[ "allies" ] ); + level.flagbasefxid[ "axis" ] = loadfx( "misc/fx_ui_flagbase_" + game[ "axis" ] ); + setclientnamemode( "auto_change" ); + allowed[ 0 ] = "dom"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 1, 1, 1 ); + level.spawnmaxs = ( 1, 1, 1 ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_dom_spawn_allies_start" ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_dom_spawn_axis_start" ); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.spawn_all = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_dom_spawn" ); + level.spawn_start = []; + _a194 = level.teams; + _k194 = getFirstArrayKey( _a194 ); + while ( isDefined( _k194 ) ) + { + team = _a194[ _k194 ]; + level.spawn_start[ team ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_dom_spawn_" + team + "_start" ); + _k194 = getNextArrayKey( _a194, _k194 ); + } + flagspawns = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_dom_spawn_flag_a" ); + level.startpos[ "allies" ] = level.spawn_start[ "allies" ][ 0 ].origin; + level.startpos[ "axis" ] = level.spawn_start[ "axis" ][ 0 ].origin; + if ( !isoneround() && isscoreroundbased() ) + { + maps/mp/gametypes/_globallogic_score::resetteamscores(); + } + level.spawnsystem.unifiedsideswitching = 0; + level thread watchforbflagcap(); + updategametypedvars(); + thread domflags(); + thread updatedomscores(); + level change_dom_spawns(); +} + +onspawnplayerunified() +{ + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + spawnpoint = undefined; + spawnteam = self.pers[ "team" ]; + if ( game[ "switchedsides" ] ) + { + spawnteam = getotherteam( spawnteam ); + } + if ( !level.usestartspawns ) + { + flagsowned = 0; + enemyflagsowned = 0; + enemyteam = getotherteam( self.pers[ "team" ] ); + i = 0; + while ( i < level.flags.size ) + { + team = level.flags[ i ] getflagteam(); + if ( team == self.pers[ "team" ] ) + { + flagsowned++; + i++; + continue; + } + else + { + if ( team == enemyteam ) + { + enemyflagsowned++; + } + } + i++; + } + enemyteam = getotherteam( spawnteam ); + if ( flagsowned == level.flags.size ) + { + enemybestspawnflag = level.bestspawnflag[ enemyteam ]; + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_all, getspawnsboundingflag( enemybestspawnflag ) ); + } + else if ( flagsowned > 0 ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_all, getboundaryflagspawns( spawnteam ) ); + } + else + { + bestflag = undefined; + if ( enemyflagsowned > 0 && enemyflagsowned < level.flags.size ) + { + bestflag = getunownedflagneareststart( spawnteam ); + } + if ( !isDefined( bestflag ) ) + { + bestflag = level.bestspawnflag[ spawnteam ]; + } + level.bestspawnflag[ spawnteam ] = bestflag; + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_all, bestflag.nearbyspawns ); + } + } + if ( !isDefined( spawnpoint ) ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_random( level.spawn_start[ spawnteam ] ); + } +/# + assert( isDefined( spawnpoint ) ); +#/ + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "dom" ); + } +} + +onendgame( winningteam ) +{ + i = 0; + while ( i < level.domflags.size ) + { + domflag = level.domflags[ i ]; + domflag maps/mp/gametypes/_gameobjects::allowuse( "none" ); + if ( isDefined( domflag.singleowner ) && domflag.singleowner == 1 ) + { + team = domflag maps/mp/gametypes/_gameobjects::getownerteam(); + label = domflag maps/mp/gametypes/_gameobjects::getlabel(); + maps/mp/_challenges::holdflagentirematch( team, label ); + } + i++; + } +} + +onroundendgame( roundwinner ) +{ + if ( level.roundscorecarry == 0 ) + { + _a318 = level.teams; + _k318 = getFirstArrayKey( _a318 ); + while ( isDefined( _k318 ) ) + { + team = _a318[ _k318 ]; + [[ level._setteamscore ]]( team, game[ "roundswon" ][ team ] ); + _k318 = getNextArrayKey( _a318, _k318 ); + } + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbygamestat( "roundswon" ); + } + else + { + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbyteamscore(); + } + return winner; +} + +updategametypedvars() +{ + level.flagcapturetime = getgametypesetting( "captureTime" ); + level.playercapturelpm = getgametypesetting( "maxPlayerEventsPerMinute" ); + level.flagcapturelpm = getgametypesetting( "maxObjectiveEventsPerMinute" ); + level.playeroffensivemax = getgametypesetting( "maxPlayerOffensive" ); + level.playerdefensivemax = getgametypesetting( "maxPlayerDefensive" ); +} + +domflags() +{ + level.laststatus[ "allies" ] = 0; + level.laststatus[ "axis" ] = 0; + level.flagmodel[ "allies" ] = maps/mp/teams/_teams::getteamflagmodel( "allies" ); + level.flagmodel[ "axis" ] = maps/mp/teams/_teams::getteamflagmodel( "axis" ); + level.flagmodel[ "neutral" ] = maps/mp/teams/_teams::getteamflagmodel( "neutral" ); + precachemodel( level.flagmodel[ "allies" ] ); + precachemodel( level.flagmodel[ "axis" ] ); + precachemodel( level.flagmodel[ "neutral" ] ); + precachestring( &"MP_CAPTURING_FLAG" ); + precachestring( &"MP_LOSING_FLAG" ); + precachestring( &"MP_DOM_YOUR_FLAG_WAS_CAPTURED" ); + precachestring( &"MP_DOM_ENEMY_FLAG_CAPTURED" ); + precachestring( &"MP_DOM_NEUTRAL_FLAG_CAPTURED" ); + precachestring( &"MP_ENEMY_FLAG_CAPTURED_BY" ); + precachestring( &"MP_NEUTRAL_FLAG_CAPTURED_BY" ); + precachestring( &"MP_FRIENDLY_FLAG_CAPTURED_BY" ); + precachestring( &"MP_DOM_FLAG_A_CAPTURED_BY" ); + precachestring( &"MP_DOM_FLAG_B_CAPTURED_BY" ); + precachestring( &"MP_DOM_FLAG_C_CAPTURED_BY" ); + precachestring( &"MP_DOM_FLAG_D_CAPTURED_BY" ); + precachestring( &"MP_DOM_FLAG_E_CAPTURED_BY" ); + primaryflags = getentarray( "flag_primary", "targetname" ); + secondaryflags = getentarray( "flag_secondary", "targetname" ); + if ( ( primaryflags.size + secondaryflags.size ) < 2 ) + { +/# + println( "^1Not enough domination flags found in level!" ); +#/ + maps/mp/gametypes/_callbacksetup::abortlevel(); + return; + } + level.flags = []; + index = 0; + while ( index < primaryflags.size ) + { + level.flags[ level.flags.size ] = primaryflags[ index ]; + index++; + } + index = 0; + while ( index < secondaryflags.size ) + { + level.flags[ level.flags.size ] = secondaryflags[ index ]; + index++; + } + level.domflags = []; + index = 0; + while ( index < level.flags.size ) + { + trigger = level.flags[ index ]; + if ( isDefined( trigger.target ) ) + { + visuals[ 0 ] = getent( trigger.target, "targetname" ); + } + else + { + visuals[ 0 ] = spawn( "script_model", trigger.origin ); + visuals[ 0 ].angles = trigger.angles; + } + visuals[ 0 ] setmodel( level.flagmodel[ "neutral" ] ); + name = istring( trigger.script_label ); + precachestring( name ); + domflag = maps/mp/gametypes/_gameobjects::createuseobject( "neutral", trigger, visuals, ( 1, 1, 1 ), name ); + domflag maps/mp/gametypes/_gameobjects::allowuse( "enemy" ); + domflag maps/mp/gametypes/_gameobjects::setusetime( level.flagcapturetime ); + domflag maps/mp/gametypes/_gameobjects::setusetext( &"MP_CAPTURING_FLAG" ); + label = domflag maps/mp/gametypes/_gameobjects::getlabel(); + domflag.label = label; + domflag.flagindex = trigger.script_index; + domflag maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + domflag.onuse = ::onuse; + domflag.onbeginuse = ::onbeginuse; + domflag.onuseupdate = ::onuseupdate; + domflag.onenduse = ::onenduse; + domflag.onupdateuserate = ::onupdateuserate; + tracestart = visuals[ 0 ].origin + vectorScale( ( 1, 1, 1 ), 32 ); + traceend = visuals[ 0 ].origin + vectorScale( ( 1, 1, 1 ), 32 ); + trace = bullettrace( tracestart, traceend, 0, undefined ); + upangles = vectorToAngle( trace[ "normal" ] ); + domflag.baseeffectforward = anglesToForward( upangles ); + domflag.baseeffectright = anglesToRight( upangles ); + domflag.baseeffectpos = trace[ "position" ]; + level.flags[ index ].useobj = domflag; + level.flags[ index ].adjflags = []; + level.flags[ index ].nearbyspawns = []; + domflag.levelflag = level.flags[ index ]; + level.domflags[ level.domflags.size ] = domflag; + index++; + } + level.bestspawnflag = []; + level.bestspawnflag[ "allies" ] = getunownedflagneareststart( "allies", undefined ); + level.bestspawnflag[ "axis" ] = getunownedflagneareststart( "axis", level.bestspawnflag[ "allies" ] ); + index = 0; + while ( index < level.domflags.size ) + { + level.domflags[ index ] createflagspawninfluencers(); + index++; + } + flagsetup(); +/# + thread domdebug(); +#/ +} + +getunownedflagneareststart( team, excludeflag ) +{ + best = undefined; + bestdistsq = undefined; + i = 0; + while ( i < level.flags.size ) + { + flag = level.flags[ i ]; + if ( flag getflagteam() != "neutral" ) + { + i++; + continue; + } + else + { + distsq = distancesquared( flag.origin, level.startpos[ team ] ); + if ( isDefined( excludeflag ) && flag != excludeflag || !isDefined( best ) && distsq < bestdistsq ) + { + bestdistsq = distsq; + best = flag; + } + } + i++; + } + return best; +} + +domdebug() +{ +/# + while ( 1 ) + { + while ( getDvar( #"9F76D073" ) != "1" ) + { + wait 2; + } + while ( 1 ) + { + if ( getDvar( #"9F76D073" ) != "1" ) + { + break; + } + else + { + i = 0; + while ( i < level.flags.size ) + { + j = 0; + while ( j < level.flags[ i ].adjflags.size ) + { + line( level.flags[ i ].origin, level.flags[ i ].adjflags[ j ].origin, ( 1, 1, 1 ) ); + j++; + } + j = 0; + while ( j < level.flags[ i ].nearbyspawns.size ) + { + line( level.flags[ i ].origin, level.flags[ i ].nearbyspawns[ j ].origin, ( 0,2, 0,2, 0,6 ) ); + j++; + } + if ( level.flags[ i ] == level.bestspawnflag[ "allies" ] ) + { + print3d( level.flags[ i ].origin, "allies best spawn flag" ); + } + if ( level.flags[ i ] == level.bestspawnflag[ "axis" ] ) + { + print3d( level.flags[ i ].origin, "axis best spawn flag" ); + } + i++; + } + wait 0,05; + } + } +#/ + } +} + +onbeginuse( player ) +{ + ownerteam = self maps/mp/gametypes/_gameobjects::getownerteam(); + self.didstatusnotify = 0; + if ( ownerteam == "allies" ) + { + otherteam = "axis"; + } + else + { + otherteam = "allies"; + } + if ( ownerteam == "neutral" ) + { + otherteam = getotherteam( player.pers[ "team" ] ); + statusdialog( "securing" + self.label, player.pers[ "team" ], "gamemode_changing" + self.label ); + return; + } +} + +onuseupdate( team, progress, change ) +{ + if ( progress > 0,05 && change && !self.didstatusnotify ) + { + ownerteam = self maps/mp/gametypes/_gameobjects::getownerteam(); + if ( ownerteam == "neutral" ) + { + otherteam = getotherteam( team ); + statusdialog( "securing" + self.label, team, "gamemode_changing" + self.label ); + } + else + { + statusdialog( "losing" + self.label, ownerteam, "gamemode_changing" + self.label ); + statusdialog( "securing" + self.label, team, "gamemode_changing" + self.label ); + } + self.didstatusnotify = 1; + } +} + +flushalldialog() +{ + maps/mp/gametypes/_globallogic_audio::flushgroupdialog( "gamemode_objective_a" ); + maps/mp/gametypes/_globallogic_audio::flushgroupdialog( "gamemode_objective_b" ); + maps/mp/gametypes/_globallogic_audio::flushgroupdialog( "gamemode_objective_c" ); + maps/mp/gametypes/_globallogic_audio::flushgroupdialog( "gamemode_changing_a" ); + maps/mp/gametypes/_globallogic_audio::flushgroupdialog( "gamemode_changing_b" ); + maps/mp/gametypes/_globallogic_audio::flushgroupdialog( "gamemode_changing_c" ); +} + +statusdialog( dialog, team, group, flushgroup ) +{ + if ( isDefined( flushgroup ) ) + { + maps/mp/gametypes/_globallogic_audio::flushgroupdialog( flushgroup ); + } + maps/mp/gametypes/_globallogic_audio::leaderdialog( dialog, team, group ); +} + +onenduse( team, player, success ) +{ + if ( !success ) + { + maps/mp/gametypes/_globallogic_audio::flushgroupdialog( "gamemode_changing" + self.label ); + } +} + +resetflagbaseeffect() +{ + if ( isDefined( self.baseeffect ) ) + { + self.baseeffect delete(); + } + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + if ( team != "axis" && team != "allies" ) + { + return; + } + fxid = level.flagbasefxid[ team ]; + self.baseeffect = spawnfx( fxid, self.baseeffectpos, self.baseeffectforward, self.baseeffectright ); + triggerfx( self.baseeffect ); +} + +onuse( player ) +{ + level notify( "flag_captured" ); + team = player.pers[ "team" ]; + oldteam = self maps/mp/gametypes/_gameobjects::getownerteam(); + label = self maps/mp/gametypes/_gameobjects::getlabel(); + player logstring( "flag captured: " + self.label ); + self maps/mp/gametypes/_gameobjects::setownerteam( team ); + self.visuals[ 0 ] setmodel( level.flagmodel[ team ] ); + setdvar( "scr_obj" + self maps/mp/gametypes/_gameobjects::getlabel(), team ); + self resetflagbaseeffect(); + level.usestartspawns = 0; +/# + assert( team != "neutral" ); +#/ + isbflag = 0; + string = &""; + switch( label ) + { + case "_a": + string = &"MP_DOM_FLAG_A_CAPTURED_BY"; + break; + case "_b": + string = &"MP_DOM_FLAG_B_CAPTURED_BY"; + isbflag = 1; + break; + case "_c": + string = &"MP_DOM_FLAG_C_CAPTURED_BY"; + break; + case "_d": + string = &"MP_DOM_FLAG_D_CAPTURED_BY"; + break; + case "_e": + string = &"MP_DOM_FLAG_E_CAPTURED_BY"; + break; + default: + } +/# + assert( string != &"" ); +#/ + touchlist = []; + touchkeys = getarraykeys( self.touchlist[ team ] ); + i = 0; + while ( i < touchkeys.size ) + { + touchlist[ touchkeys[ i ] ] = self.touchlist[ team ][ touchkeys[ i ] ]; + i++; + } + thread give_capture_credit( touchlist, string, oldteam, isbflag ); + bbprint( "mpobjective", "gametime %d objtype %s label %s team %s", getTime(), "dom_capture", label, team ); + if ( oldteam == "neutral" ) + { + self.singleowner = 1; + otherteam = getotherteam( team ); + thread printandsoundoneveryone( team, undefined, &"", undefined, "mp_war_objective_taken" ); + thread playsoundonplayers( "mus_dom_captured" + "_" + level.teampostfix[ team ] ); + if ( getteamflagcount( team ) == level.flags.size ) + { + statusdialog( "secure_all", team, "gamemode_objective" ); + statusdialog( "lost_all", otherteam, "gamemode_objective" ); + flushalldialog(); + } + else statusdialog( "secured" + self.label, team, "gamemode_objective" + self.label, "gamemode_changing" + self.label ); + statusdialog( "enemy" + self.label, otherteam, "gamemode_objective" + self.label, "gamemode_changing" + self.label ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagcapture_sting_enemy", otherteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagcapture_sting_friend", team ); + } + else + { + self.singleowner = 0; + thread printandsoundoneveryone( team, oldteam, &"", &"", "mp_war_objective_taken", "mp_war_objective_lost", "" ); + if ( getteamflagcount( team ) == level.flags.size ) + { + statusdialog( "secure_all", team, "gamemode_objective" ); + statusdialog( "lost_all", oldteam, "gamemode_objective" ); + flushalldialog(); + } + else + { + statusdialog( "secured" + self.label, team, "gamemode_objective" + self.label, "gamemode_changing" + self.label ); + if ( randomint( 2 ) ) + { + statusdialog( "lost" + self.label, oldteam, "gamemode_objective" + self.label, "gamemode_changing" + self.label ); + } + else + { + statusdialog( "enemy" + self.label, oldteam, "gamemode_objective" + self.label, "gamemode_changing" + self.label ); + } + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagcapture_sting_enemy", oldteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagcapture_sting_friend", team ); + } + level.bestspawnflag[ oldteam ] = self.levelflag; + } + if ( dominated_challenge_check() ) + { + level thread totaldomination( team ); + } + self update_spawn_influencers( team ); + level change_dom_spawns(); + } +} + +totaldomination( team ) +{ + level endon( "flag_captured" ); + level endon( "game_ended" ); + wait 180; + maps/mp/_challenges::totaldomination( team ); +} + +watchforbflagcap() +{ + level endon( "game_ended" ); + level endon( "endWatchForBFlagCapAfterTime" ); + level thread endwatchforbflagcapaftertime( 60 ); + for ( ;; ) + { + level waittill( "b_flag_captured", player ); + player maps/mp/_challenges::capturedbfirstminute(); + } +} + +endwatchforbflagcapaftertime( time ) +{ + level endon( "game_ended" ); + wait 60; + level notify( "endWatchForBFlagCapAfterTime" ); +} + +give_capture_credit( touchlist, string, lastownerteam, isbflag ) +{ + time = getTime(); + wait 0,05; + maps/mp/gametypes/_globallogic_utils::waittillslowprocessallowed(); + self updatecapsperminute( lastownerteam ); + players = getarraykeys( touchlist ); + i = 0; + while ( i < players.size ) + { + player_from_touchlist = touchlist[ players[ i ] ].player; + player_from_touchlist updatecapsperminute( lastownerteam ); + if ( !isscoreboosting( player_from_touchlist, self ) ) + { + player_from_touchlist maps/mp/_challenges::capturedobjective( time ); + if ( lastownerteam == "neutral" ) + { + if ( isbflag ) + { + maps/mp/_scoreevents::processscoreevent( "dom_point_neutral_b_secured", player_from_touchlist ); + } + else + { + maps/mp/_scoreevents::processscoreevent( "dom_point_neutral_secured", player_from_touchlist ); + } + } + else + { + maps/mp/_scoreevents::processscoreevent( "dom_point_secured", player_from_touchlist ); + } + player_from_touchlist recordgameevent( "capture" ); + if ( isbflag ) + { + level notify( "b_flag_captured" ); + } + if ( isDefined( player_from_touchlist.pers[ "captures" ] ) ) + { + player_from_touchlist.pers[ "captures" ]++; + player_from_touchlist.captures = player_from_touchlist.pers[ "captures" ]; + } + maps/mp/_demo::bookmark( "event", getTime(), player_from_touchlist ); + player_from_touchlist addplayerstatwithgametype( "CAPTURES", 1 ); + } + else + { +/# + player_from_touchlist iprintlnbold( "GAMETYPE DEBUG: NOT GIVING YOU CAPTURE CREDIT AS BOOSTING PREVENTION" ); +#/ + } + level thread maps/mp/_popups::displayteammessagetoall( string, player_from_touchlist ); + i++; + } +} + +delayedleaderdialog( sound, team, label ) +{ + wait 0,1; + maps/mp/gametypes/_globallogic_utils::waittillslowprocessallowed(); + if ( !isDefined( label ) ) + { + label = ""; + } + maps/mp/gametypes/_globallogic_audio::leaderdialog( sound, team, "gamemode_objective" + label ); +} + +updatedomscores() +{ + while ( !level.gameended ) + { + numownedflags = 0; + scoring_teams = []; + numflags = getteamflagcount( "allies" ); + numownedflags += numflags; + if ( numflags ) + { + scoring_teams[ scoring_teams.size ] = "allies"; + maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective_delaypostprocessing( "allies", numflags ); + } + numflags = getteamflagcount( "axis" ); + numownedflags += numflags; + if ( numflags ) + { + scoring_teams[ scoring_teams.size ] = "axis"; + maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective_delaypostprocessing( "axis", numflags ); + } + if ( numownedflags ) + { + maps/mp/gametypes/_globallogic_score::postprocessteamscores( scoring_teams ); + } + onscoreclosemusic(); + timepassed = maps/mp/gametypes/_globallogic_utils::gettimepassed(); + if ( ( timepassed / 1000 ) > 120 && numownedflags < 2 && ( timepassed / 1000 ) > 300 && numownedflags < 3 && gamemodeismode( level.gamemode_public_match ) ) + { + thread maps/mp/gametypes/_globallogic::endgame( "tie", game[ "strings" ][ "time_limit_reached" ] ); + return; + } + wait 5; + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + } +} + +onscoreclosemusic() +{ + axisscore = [[ level._getteamscore ]]( "axis" ); + alliedscore = [[ level._getteamscore ]]( "allies" ); + scorelimit = level.scorelimit; + scorethreshold = scorelimit * 0,1; + scoredif = abs( axisscore - alliedscore ); + scorethresholdstart = abs( scorelimit - scorethreshold ); + scorelimitcheck = scorelimit - 10; + if ( !isDefined( level.playingactionmusic ) ) + { + level.playingactionmusic = 0; + } + if ( alliedscore > axisscore ) + { + currentscore = alliedscore; + } + else + { + currentscore = axisscore; + } +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System Domination - scoreDif " + scoredif ); + println( "Music System Domination - axisScore " + axisscore ); + println( "Music System Domination - alliedScore " + alliedscore ); + println( "Music System Domination - scoreLimit " + scorelimit ); + println( "Music System Domination - currentScore " + currentscore ); + println( "Music System Domination - scoreThreshold " + scorethreshold ); + println( "Music System Domination - scoreDif " + scoredif ); + println( "Music System Domination - scoreThresholdStart " + scorethresholdstart ); +#/ + } + if ( scoredif <= scorethreshold && scorethresholdstart <= currentscore && level.playingactionmusic != 1 ) + { + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "TIME_OUT", "both" ); + thread maps/mp/gametypes/_globallogic_audio::actionmusicset(); + } + else + { + return; + } +} + +onroundswitch() +{ + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + game[ "switchedsides" ] = !game[ "switchedsides" ]; + if ( level.roundscorecarry == 0 ) + { + [[ level._setteamscore ]]( "allies", game[ "roundswon" ][ "allies" ] ); + [[ level._setteamscore ]]( "axis", game[ "roundswon" ][ "axis" ] ); + } +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + scoreeventprocessed = 0; + if ( attacker.touchtriggers.size && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + triggerids = getarraykeys( attacker.touchtriggers ); + ownerteam = attacker.touchtriggers[ triggerids[ 0 ] ].useobj.ownerteam; + team = attacker.pers[ "team" ]; + if ( team != ownerteam ) + { + maps/mp/_scoreevents::processscoreevent( "kill_enemy_while_capping_dom", attacker, undefined, sweapon ); + scoreeventprocessed = 1; + } + } + index = 0; + while ( index < level.flags.size ) + { + flagteam = "invalidTeam"; + inflagzone = 0; + defendedflag = 0; + offendedflag = 0; + flagorigin = level.flags[ index ].origin; + level.defaultoffenseradius = 300; + dist = distance2d( self.origin, flagorigin ); + if ( dist < level.defaultoffenseradius ) + { + inflagzone = 1; + if ( level.flags[ index ] getflagteam() == attacker.pers[ "team" ] || level.flags[ index ] getflagteam() == "neutral" ) + { + defendedflag = 1; + break; + } + else + { + offendedflag = 1; + } + } + dist = distance2d( attacker.origin, flagorigin ); + if ( dist < level.defaultoffenseradius ) + { + inflagzone = 1; + if ( level.flags[ index ] getflagteam() == attacker.pers[ "team" ] || level.flags[ index ] getflagteam() == "neutral" ) + { + defendedflag = 1; + break; + } + else + { + offendedflag = 1; + } + } + if ( inflagzone && isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + if ( offendedflag ) + { + if ( !isDefined( attacker.dom_defends ) ) + { + attacker.dom_defends = 0; + } + attacker.dom_defends++; + if ( level.playerdefensivemax >= attacker.dom_defends ) + { + attacker addplayerstatwithgametype( "OFFENDS", 1 ); + if ( !scoreeventprocessed ) + { + maps/mp/_scoreevents::processscoreevent( "killed_defender", attacker, undefined, sweapon ); + } + self recordkillmodifier( "defending" ); + break; + } + else /# + attacker iprintlnbold( "GAMETYPE DEBUG: NOT GIVING YOU DEFENSIVE CREDIT AS BOOSTING PREVENTION" ); +#/ + } + if ( defendedflag ) + { + if ( !isDefined( attacker.dom_offends ) ) + { + attacker.dom_offends = 0; + } + attacker thread updateattackermultikills(); + attacker.dom_offends++; + if ( level.playeroffensivemax >= attacker.dom_offends ) + { + attacker.pers[ "defends" ]++; + attacker.defends = attacker.pers[ "defends" ]; + attacker addplayerstatwithgametype( "DEFENDS", 1 ); + attacker recordgameevent( "return" ); + attacker maps/mp/_challenges::killedzoneattacker( sweapon ); + if ( !scoreeventprocessed ) + { + maps/mp/_scoreevents::processscoreevent( "killed_attacker", attacker, undefined, sweapon ); + } + self recordkillmodifier( "assaulting" ); + break; + } + else /# + attacker iprintlnbold( "GAMETYPE DEBUG: NOT GIVING YOU OFFENSIVE CREDIT AS BOOSTING PREVENTION" ); +#/ + } + } + index++; + } + if ( self.touchtriggers.size && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + triggerids = getarraykeys( self.touchtriggers ); + ownerteam = self.touchtriggers[ triggerids[ 0 ] ].useobj.ownerteam; + team = self.pers[ "team" ]; + if ( team != ownerteam ) + { + flag = self.touchtriggers[ triggerids[ 0 ] ].useobj; + if ( isDefined( flag.contested ) && flag.contested == 1 ) + { + attacker killwhilecontesting( flag ); + } + } + } + } +} + +killwhilecontesting( flag ) +{ + self notify( "killWhileContesting" ); + self endon( "killWhileContesting" ); + self endon( "disconnect" ); + killtime = getTime(); + playerteam = self.pers[ "team" ]; + if ( !isDefined( self.clearenemycount ) ) + { + self.clearenemycount = 0; + } + self.clearenemycount++; + flag waittill( "contest_over" ); + if ( playerteam != self.pers[ "team" ] || isDefined( self.spawntime ) && killtime < self.spawntime ) + { + self.clearenemycount = 0; + return; + } + if ( flag.ownerteam != playerteam && flag.ownerteam != "neutral" ) + { + self.clearenemycount = 0; + return; + } + if ( self.clearenemycount >= 2 && ( killtime + 200 ) > getTime() ) + { + maps/mp/_scoreevents::processscoreevent( "clear_2_attackers", self ); + } + self.clearenemycount = 0; +} + +updateattackermultikills() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + self notify( "updateDomRecentKills" ); + self endon( "updateDomRecentKills" ); + if ( !isDefined( self.recentdomattackerkillcount ) ) + { + self.recentdomattackerkillcount = 0; + } + self.recentdomattackerkillcount++; + wait 4; + if ( self.recentdomattackerkillcount > 1 ) + { + self maps/mp/_challenges::domattackermultikill( self.recentdomattackerkillcount ); + } + self.recentdomattackerkillcount = 0; +} + +getteamflagcount( team ) +{ + score = 0; + i = 0; + while ( i < level.flags.size ) + { + if ( level.domflags[ i ] maps/mp/gametypes/_gameobjects::getownerteam() == team ) + { + score++; + } + i++; + } + return score; +} + +getflagteam() +{ + return self.useobj maps/mp/gametypes/_gameobjects::getownerteam(); +} + +getboundaryflags() +{ + bflags = []; + i = 0; + while ( i < level.flags.size ) + { + j = 0; + while ( j < level.flags[ i ].adjflags.size ) + { + if ( level.flags[ i ].useobj maps/mp/gametypes/_gameobjects::getownerteam() != level.flags[ i ].adjflags[ j ].useobj maps/mp/gametypes/_gameobjects::getownerteam() ) + { + bflags[ bflags.size ] = level.flags[ i ]; + i++; + continue; + } + else + { + j++; + } + } + i++; + } + return bflags; +} + +getboundaryflagspawns( team ) +{ + spawns = []; + bflags = getboundaryflags(); + i = 0; + while ( i < bflags.size ) + { + if ( isDefined( team ) && bflags[ i ] getflagteam() != team ) + { + i++; + continue; + } + else + { + j = 0; + while ( j < bflags[ i ].nearbyspawns.size ) + { + spawns[ spawns.size ] = bflags[ i ].nearbyspawns[ j ]; + j++; + } + } + i++; + } + return spawns; +} + +getspawnsboundingflag( avoidflag ) +{ + spawns = []; + i = 0; + while ( i < level.flags.size ) + { + flag = level.flags[ i ]; + if ( flag == avoidflag ) + { + i++; + continue; + } + else isbounding = 0; + j = 0; + while ( j < flag.adjflags.size ) + { + if ( flag.adjflags[ j ] == avoidflag ) + { + isbounding = 1; + break; + } + else + { + j++; + } + } + if ( !isbounding ) + { + i++; + continue; + } + else + { + j = 0; + while ( j < flag.nearbyspawns.size ) + { + spawns[ spawns.size ] = flag.nearbyspawns[ j ]; + j++; + } + } + i++; + } + return spawns; +} + +getownedandboundingflagspawns( team ) +{ + spawns = []; + i = 0; + while ( i < level.flags.size ) + { + if ( level.flags[ i ] getflagteam() == team ) + { + s = 0; + while ( s < level.flags[ i ].nearbyspawns.size ) + { + spawns[ spawns.size ] = level.flags[ i ].nearbyspawns[ s ]; + s++; + } + } + else j = 0; + while ( j < level.flags[ i ].adjflags.size ) + { + if ( level.flags[ i ].adjflags[ j ] getflagteam() == team ) + { + s = 0; + while ( s < level.flags[ i ].nearbyspawns.size ) + { + spawns[ spawns.size ] = level.flags[ i ].nearbyspawns[ s ]; + s++; + } + } + else j++; + } + i++; + } + return spawns; +} + +getownedflagspawns( team ) +{ + spawns = []; + i = 0; + while ( i < level.flags.size ) + { + while ( level.flags[ i ] getflagteam() == team ) + { + s = 0; + while ( s < level.flags[ i ].nearbyspawns.size ) + { + spawns[ spawns.size ] = level.flags[ i ].nearbyspawns[ s ]; + s++; + } + } + i++; + } + return spawns; +} + +flagsetup() +{ + maperrors = []; + descriptorsbylinkname = []; + descriptors = getentarray( "flag_descriptor", "targetname" ); + flags = level.flags; + i = 0; + while ( i < level.domflags.size ) + { + closestdist = undefined; + closestdesc = undefined; + j = 0; + while ( j < descriptors.size ) + { + dist = distance( flags[ i ].origin, descriptors[ j ].origin ); + if ( !isDefined( closestdist ) || dist < closestdist ) + { + closestdist = dist; + closestdesc = descriptors[ j ]; + } + j++; + } + if ( !isDefined( closestdesc ) ) + { + maperrors[ maperrors.size ] = "there is no flag_descriptor in the map! see explanation in dom.gsc"; + break; + } + else + { + if ( isDefined( closestdesc.flag ) ) + { + maperrors[ maperrors.size ] = "flag_descriptor with script_linkname "" + closestdesc.script_linkname + "" is nearby more than one flag; is there a unique descriptor near each flag?"; + i++; + continue; + } + else + { + flags[ i ].descriptor = closestdesc; + closestdesc.flag = flags[ i ]; + descriptorsbylinkname[ closestdesc.script_linkname ] = closestdesc; + } + i++; + } + } + while ( maperrors.size == 0 ) + { + i = 0; + while ( i < flags.size ) + { + if ( isDefined( flags[ i ].descriptor.script_linkto ) ) + { + adjdescs = strtok( flags[ i ].descriptor.script_linkto, " " ); + } + else + { + adjdescs = []; + } + j = 0; + while ( j < adjdescs.size ) + { + otherdesc = descriptorsbylinkname[ adjdescs[ j ] ]; + if ( !isDefined( otherdesc ) || otherdesc.targetname != "flag_descriptor" ) + { + maperrors[ maperrors.size ] = "flag_descriptor with script_linkname "" + flags[ i ].descriptor.script_linkname + "" linked to "" + adjdescs[ j ] + "" which does not exist as a script_linkname of any other entity with a targetname of flag_descriptor (or, if it does, that flag_descriptor has not been assigned to a flag)"; + j++; + continue; + } + else + { + adjflag = otherdesc.flag; + if ( adjflag == flags[ i ] ) + { + maperrors[ maperrors.size ] = "flag_descriptor with script_linkname "" + flags[ i ].descriptor.script_linkname + "" linked to itself"; + j++; + continue; + } + else + { + flags[ i ].adjflags[ flags[ i ].adjflags.size ] = adjflag; + } + } + j++; + } + i++; + } + } + spawnpoints = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_dom_spawn" ); + i = 0; + while ( i < spawnpoints.size ) + { + if ( isDefined( spawnpoints[ i ].script_linkto ) ) + { + desc = descriptorsbylinkname[ spawnpoints[ i ].script_linkto ]; + if ( !isDefined( desc ) || desc.targetname != "flag_descriptor" ) + { + maperrors[ maperrors.size ] = "Spawnpoint at " + spawnpoints[ i ].origin + "" linked to "" + spawnpoints[ i ].script_linkto + "" which does not exist as a script_linkname of any entity with a targetname of flag_descriptor (or, if it does, that flag_descriptor has not been assigned to a flag)"; + i++; + continue; + } + else + { + nearestflag = desc.flag; + } + else + { + nearestflag = undefined; + nearestdist = undefined; + j = 0; + while ( j < flags.size ) + { + dist = distancesquared( flags[ j ].origin, spawnpoints[ i ].origin ); + if ( !isDefined( nearestflag ) || dist < nearestdist ) + { + nearestflag = flags[ j ]; + nearestdist = dist; + } + j++; + } + } + nearestflag.nearbyspawns[ nearestflag.nearbyspawns.size ] = spawnpoints[ i ]; + } + i++; + } + if ( maperrors.size > 0 ) + { +/# + println( "^1------------ Map Errors ------------" ); + i = 0; + while ( i < maperrors.size ) + { + println( maperrors[ i ] ); + i++; + } + println( "^1------------------------------------" ); + maps/mp/_utility::error( "Map errors. See above" ); +#/ + maps/mp/gametypes/_callbacksetup::abortlevel(); + return; + } +} + +createflagspawninfluencers() +{ + ss = level.spawnsystem; + flag_index = 0; + while ( flag_index < level.flags.size ) + { + if ( level.domflags[ flag_index ] == self ) + { + break; + } + else + { + flag_index++; + } + } + abc = []; + abc[ 0 ] = "A"; + abc[ 1 ] = "B"; + abc[ 2 ] = "C"; + self.owned_flag_influencer = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.trigger.origin, ss.dom_owned_flag_influencer_radius[ flag_index ], ss.dom_owned_flag_influencer_score[ flag_index ], 0, "dom_owned_flag_" + abc[ flag_index ] + ",r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ss.dom_owned_flag_influencer_score_curve ) ); + self.neutral_flag_influencer = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.trigger.origin, ss.dom_unowned_flag_influencer_radius, ss.dom_unowned_flag_influencer_score, 0, "dom_unowned_flag,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ss.dom_owned_flag_influencer_score_curve ) ); + self.enemy_flag_influencer = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.trigger.origin, ss.dom_enemy_flag_influencer_radius[ flag_index ], ss.dom_enemy_flag_influencer_score[ flag_index ], 0, "dom_enemy_flag_" + abc[ flag_index ] + ",r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ss.dom_enemy_flag_influencer_score_curve ) ); + self update_spawn_influencers( "neutral" ); +} + +update_spawn_influencers( team ) +{ +/# + assert( isDefined( self.neutral_flag_influencer ) ); +#/ +/# + assert( isDefined( self.owned_flag_influencer ) ); +#/ +/# + assert( isDefined( self.enemy_flag_influencer ) ); +#/ + if ( team == "neutral" ) + { + enableinfluencer( self.neutral_flag_influencer, 1 ); + enableinfluencer( self.owned_flag_influencer, 0 ); + enableinfluencer( self.enemy_flag_influencer, 0 ); + } + else + { + enableinfluencer( self.neutral_flag_influencer, 0 ); + enableinfluencer( self.owned_flag_influencer, 1 ); + enableinfluencer( self.enemy_flag_influencer, 1 ); + setinfluencerteammask( self.owned_flag_influencer, getteammask( team ) ); + setinfluencerteammask( self.enemy_flag_influencer, getotherteamsmask( team ) ); + } +} + +dom_gamemodespawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.dom_owned_flag_influencer_score = []; + ss.dom_owned_flag_influencer_radius = []; + ss.dom_owned_flag_influencer_score[ 0 ] = set_dvar_float_if_unset( "scr_spawn_dom_owned_flag_A_influencer_score", "10", reset_dvars ); + ss.dom_owned_flag_influencer_radius[ 0 ] = set_dvar_float_if_unset( "scr_spawn_dom_owned_flag_A_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.dom_owned_flag_influencer_score[ 1 ] = set_dvar_float_if_unset( "scr_spawn_dom_owned_flag_B_influencer_score", "10", reset_dvars ); + ss.dom_owned_flag_influencer_radius[ 1 ] = set_dvar_float_if_unset( "scr_spawn_dom_owned_flag_B_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.dom_owned_flag_influencer_score[ 2 ] = set_dvar_float_if_unset( "scr_spawn_dom_owned_flag_C_influencer_score", "10", reset_dvars ); + ss.dom_owned_flag_influencer_radius[ 2 ] = set_dvar_float_if_unset( "scr_spawn_dom_owned_flag_C_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.dom_owned_flag_influencer_score_curve = set_dvar_if_unset( "scr_spawn_dom_owned_flag_influencer_score_curve", "constant", reset_dvars ); + ss.dom_enemy_flag_influencer_score = []; + ss.dom_enemy_flag_influencer_radius = []; + ss.dom_enemy_flag_influencer_score[ 0 ] = set_dvar_float_if_unset( "scr_spawn_dom_enemy_flag_A_influencer_score", "-50", reset_dvars ); + ss.dom_enemy_flag_influencer_radius[ 0 ] = set_dvar_float_if_unset( "scr_spawn_dom_enemy_flag_A_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.dom_enemy_flag_influencer_score[ 1 ] = set_dvar_float_if_unset( "scr_spawn_dom_enemy_flag_B_influencer_score", "-50", reset_dvars ); + ss.dom_enemy_flag_influencer_radius[ 1 ] = set_dvar_float_if_unset( "scr_spawn_dom_enemy_flag_B_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.dom_enemy_flag_influencer_score[ 2 ] = set_dvar_float_if_unset( "scr_spawn_dom_enemy_flag_C_influencer_score", "-50", reset_dvars ); + ss.dom_enemy_flag_influencer_radius[ 2 ] = set_dvar_float_if_unset( "scr_spawn_dom_enemy_flag_C_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.dom_enemy_flag_influencer_score_curve = set_dvar_if_unset( "scr_spawn_dom_enemy_flag_influencer_score_curve", "constant", reset_dvars ); + ss.dom_unowned_flag_influencer_score = set_dvar_float_if_unset( "scr_spawn_dom_unowned_flag_influencer_score", "-500", reset_dvars ); + ss.dom_unowned_flag_influencer_score_curve = set_dvar_if_unset( "scr_spawn_dom_unowned_flag_influencer_score_curve", "constant", reset_dvars ); + ss.dom_unowned_flag_influencer_radius = set_dvar_float_if_unset( "scr_spawn_dom_unowned_flag_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); +} + +addspawnpointsforflag( team, flag_team, flagspawnname ) +{ + if ( game[ "switchedsides" ] ) + { + team = getotherteam( team ); + } + otherteam = getotherteam( team ); + if ( flag_team != otherteam ) + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( team, flagspawnname ); + } +} + +change_dom_spawns() +{ + maps/mp/gametypes/_spawnlogic::clearspawnpoints(); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_dom_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_dom_spawn" ); + flag_number = level.flags.size; + if ( dominated_check() ) + { + i = 0; + while ( i < flag_number ) + { + label = level.flags[ i ].useobj maps/mp/gametypes/_gameobjects::getlabel(); + flagspawnname = "mp_dom_spawn_flag" + label; + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", flagspawnname ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", flagspawnname ); + i++; + } + } + else i = 0; + while ( i < flag_number ) + { + label = level.flags[ i ].useobj maps/mp/gametypes/_gameobjects::getlabel(); + flagspawnname = "mp_dom_spawn_flag" + label; + flag_team = level.flags[ i ] getflagteam(); + addspawnpointsforflag( "allies", flag_team, flagspawnname ); + addspawnpointsforflag( "axis", flag_team, flagspawnname ); + i++; + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); +} + +dominated_challenge_check() +{ + num_flags = level.flags.size; + allied_flags = 0; + axis_flags = 0; + i = 0; + while ( i < num_flags ) + { + flag_team = level.flags[ i ] getflagteam(); + if ( flag_team == "allies" ) + { + allied_flags++; + } + else if ( flag_team == "axis" ) + { + axis_flags++; + } + else + { + return 0; + } + if ( allied_flags > 0 && axis_flags > 0 ) + { + return 0; + } + i++; + } + return 1; +} + +dominated_check() +{ + num_flags = level.flags.size; + allied_flags = 0; + axis_flags = 0; + i = 0; + while ( i < num_flags ) + { + flag_team = level.flags[ i ] getflagteam(); + if ( flag_team == "allies" ) + { + allied_flags++; + } + else + { + if ( flag_team == "axis" ) + { + axis_flags++; + } + } + if ( allied_flags > 0 && axis_flags > 0 ) + { + return 0; + } + i++; + } + return 1; +} + +updatecapsperminute( lastownerteam ) +{ + if ( !isDefined( self.capsperminute ) ) + { + self.numcaps = 0; + self.capsperminute = 0; + } + if ( lastownerteam == "neutral" ) + { + return; + } + self.numcaps++; + minutespassed = maps/mp/gametypes/_globallogic_utils::gettimepassed() / 60000; + if ( isplayer( self ) && isDefined( self.timeplayed[ "total" ] ) ) + { + minutespassed = self.timeplayed[ "total" ] / 60; + } + self.capsperminute = self.numcaps / minutespassed; + if ( self.capsperminute > self.numcaps ) + { + self.capsperminute = self.numcaps; + } +} + +isscoreboosting( player, flag ) +{ + if ( !level.rankedmatch ) + { + return 0; + } + if ( player.capsperminute > level.playercapturelpm ) + { + return 1; + } + if ( flag.capsperminute > level.flagcapturelpm ) + { + return 1; + } + return 0; +} + +onupdateuserate() +{ + if ( !isDefined( self.contested ) ) + { + self.contested = 0; + } + numother = getnumtouchingexceptteam( self.ownerteam ); + numowners = self.numtouching[ self.claimteam ]; + previousstate = self.contested; + if ( numother > 0 && numowners > 0 ) + { + self.contested = 1; + } + else + { + if ( previousstate == 1 ) + { + self notify( "contest_over" ); + } + self.contested = 0; + } +} diff --git a/patch_mp/maps/mp/gametypes/gun.gsc b/patch_mp/maps/mp/gametypes/gun.gsc new file mode 100644 index 0000000..275863c --- /dev/null +++ b/patch_mp/maps/mp/gametypes/gun.gsc @@ -0,0 +1,406 @@ +#include maps/mp/gametypes/_persistence; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_rank; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_wager; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +main() +{ + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onplayerkilled = ::onplayerkilled; + level.onwagerawards = ::onwagerawards; + level.onendgame = ::onendgame; + game[ "dialog" ][ "gametype" ] = "gg_start"; + game[ "dialog" ][ "wm_promoted" ] = "gg_promote"; + game[ "dialog" ][ "wm_humiliation" ] = "mpl_wager_humiliate"; + game[ "dialog" ][ "wm_humiliated" ] = "sns_hum"; + level.givecustomloadout = ::givecustomloadout; + precachestring( &"MPUI_PLAYER_KILLED" ); + precachestring( &"MP_GUN_NEXT_LEVEL" ); + precachestring( &"MP_GUN_PREV_LEVEL" ); + precachestring( &"MP_GUN_PREV_LEVEL_OTHER" ); + precachestring( &"MP_HUMILIATION" ); + precachestring( &"MP_HUMILIATED" ); + precacheitem( "minigun_wager_mp" ); + precacheitem( "m32_wager_mp" ); + level.setbacksperdemotion = getgametypesetting( "setbacks" ); + gunlist = getgametypesetting( "gunSelection" ); + if ( gunlist == 3 ) + { + gunlist = randomintrange( 0, 3 ); + } + switch( gunlist ) + { + case 0: + addguntoprogression( "beretta93r_mp+tacknife" ); + addguntoprogression( "kard_dw_mp" ); + addguntoprogression( "judge_mp+steadyaim" ); + addguntoprogression( "ksg_mp+fastads" ); + addguntoprogression( "srm1216_mp+extclip" ); + addguntoprogression( "insas_mp+grip" ); + addguntoprogression( "evoskorpion_mp+steadyaim" ); + addguntoprogression( "qcw05_mp+reflex" ); + addguntoprogression( "hk416_mp+mms" ); + addguntoprogression( "xm8_mp+holo" ); + addguntoprogression( "saritch_mp+acog" ); + addguntoprogression( "qbb95_mp+rangefinder" ); + addguntoprogression( "mk48_mp+dualoptic", "dualoptic_mk48_mp+dualoptic" ); + addguntoprogression( "svu_mp+ir" ); + addguntoprogression( "dsr50_mp+vzoom" ); + addguntoprogression( "ballista_mp+is" ); + addguntoprogression( "smaw_mp" ); + addguntoprogression( "usrpg_mp" ); + addguntoprogression( "crossbow_mp" ); + addguntoprogression( "knife_ballistic_mp" ); + break; + case 1: + addguntoprogression( "fiveseven_mp" ); + addguntoprogression( "fnp45_mp" ); + addguntoprogression( "kard_mp" ); + addguntoprogression( "beretta93r_mp" ); + addguntoprogression( "judge_mp" ); + addguntoprogression( "ksg_mp" ); + addguntoprogression( "870mcs_mp" ); + addguntoprogression( "saiga12_mp" ); + addguntoprogression( "srm1216_mp" ); + addguntoprogression( "mp7_mp" ); + addguntoprogression( "evoskorpion_mp" ); + addguntoprogression( "pdw57_mp" ); + addguntoprogression( "insas_mp" ); + addguntoprogression( "vector_mp" ); + addguntoprogression( "qcw05_mp" ); + addguntoprogression( "m32_wager_mp" ); + addguntoprogression( "smaw_mp" ); + addguntoprogression( "usrpg_mp" ); + addguntoprogression( "crossbow_mp" ); + addguntoprogression( "knife_ballistic_mp" ); + break; + case 2: + addguntoprogression( "hk416_mp" ); + addguntoprogression( "scar_mp" ); + addguntoprogression( "tar21_mp" ); + addguntoprogression( "an94_mp" ); + addguntoprogression( "type95_mp" ); + addguntoprogression( "xm8_mp" ); + addguntoprogression( "sig556_mp" ); + addguntoprogression( "sa58_mp" ); + addguntoprogression( "saritch_mp" ); + addguntoprogression( "hamr_mp" ); + addguntoprogression( "lsat_mp" ); + addguntoprogression( "qbb95_mp" ); + addguntoprogression( "mk48_mp" ); + addguntoprogression( "svu_mp" ); + addguntoprogression( "as50_mp" ); + addguntoprogression( "dsr50_mp" ); + addguntoprogression( "ballista_mp+is" ); + addguntoprogression( "usrpg_mp" ); + addguntoprogression( "crossbow_mp" ); + addguntoprogression( "knife_ballistic_mp" ); + break; + } + registertimelimit( 0, 1440 ); + registerroundlimit( 0, 10 ); + registerroundwinlimit( 0, 10 ); + registernumlives( 0, 100 ); + setscoreboardcolumns( "pointstowin", "kills", "deaths", "stabs", "humiliated" ); +} + +addguntoprogression( gunname, altname ) +{ + if ( !isDefined( level.gunprogression ) ) + { + level.gunprogression = []; + } + newweapon = spawnstruct(); + newweapon.names = []; + newweapon.names[ newweapon.names.size ] = gunname; + if ( isDefined( altname ) ) + { + newweapon.names[ newweapon.names.size ] = altname; + } + level.gunprogression[ level.gunprogression.size ] = newweapon; +} + +givecustomloadout( takeallweapons, alreadyspawned ) +{ + chooserandombody = 0; + if ( !isDefined( alreadyspawned ) || !alreadyspawned ) + { + chooserandombody = 1; + } + if ( !isDefined( self.gunprogress ) ) + { + self.gunprogress = 0; + } + currentweapon = level.gunprogression[ self.gunprogress ].names[ 0 ]; + self maps/mp/gametypes/_wager::setupblankrandomplayer( takeallweapons, chooserandombody, currentweapon ); + self disableweaponcycling(); + self giveweapon( currentweapon ); + self switchtoweapon( currentweapon ); + self giveweapon( "knife_mp" ); + if ( !isDefined( alreadyspawned ) || !alreadyspawned ) + { + self setspawnweapon( currentweapon ); + } + if ( isDefined( takeallweapons ) && !takeallweapons ) + { + self thread takeoldweapons( currentweapon ); + } + else + { + self enableweaponcycling(); + } + return currentweapon; +} + +takeoldweapons( currentweapon ) +{ + self endon( "disconnect" ); + self endon( "death" ); + for ( ;; ) + { + self waittill( "weapon_change", newweapon ); + if ( newweapon != "none" ) + { + break; + } + else + { + } + } + weaponslist = self getweaponslist(); + i = 0; + while ( i < weaponslist.size ) + { + if ( weaponslist[ i ] != currentweapon && weaponslist[ i ] != "knife_mp" ) + { + self takeweapon( weaponslist[ i ] ); + } + i++; + } + self enableweaponcycling(); +} + +promoteplayer( weaponused ) +{ + self endon( "disconnect" ); + self endon( "cancel_promotion" ); + level endon( "game_ended" ); + wait 0,05; + i = 0; + while ( i < level.gunprogression[ self.gunprogress ].names.size ) + { + if ( weaponused == level.gunprogression[ self.gunprogress ].names[ i ] || weaponused == "explosive_bolt_mp" && level.gunprogression[ self.gunprogress ].names[ i ] != "crossbow_mp" || level.gunprogression[ self.gunprogress ].names[ i ] == "crossbow_mp+reflex" && level.gunprogression[ self.gunprogress ].names[ i ] == "crossbow_mp+acog" ) + { + if ( self.gunprogress < ( level.gunprogression.size - 1 ) ) + { + self.gunprogress++; + if ( isalive( self ) ) + { + self thread givecustomloadout( 0, 1 ); + } + self thread maps/mp/gametypes/_wager::queuewagerpopup( &"MPUI_PLAYER_KILLED", 0, &"MP_GUN_NEXT_LEVEL" ); + } + pointstowin = self.pers[ "pointstowin" ]; + if ( pointstowin < level.scorelimit ) + { + self maps/mp/gametypes/_globallogic_score::givepointstowin( level.gungamekillscore ); + maps/mp/_scoreevents::processscoreevent( "kill_gun", self ); + } + self.lastpromotiontime = getTime(); + return; + } + i++; + } +} + +demoteplayer() +{ + self endon( "disconnect" ); + self notify( "cancel_promotion" ); + startinggunprogress = self.gunprogress; + i = 0; + while ( i < level.setbacksperdemotion ) + { + if ( self.gunprogress <= 0 ) + { + break; + } + else + { + self maps/mp/gametypes/_globallogic_score::givepointstowin( level.gungamekillscore * -1 ); + self.gunprogress--; + + i++; + } + } + if ( startinggunprogress != self.gunprogress && isalive( self ) ) + { + self thread givecustomloadout( 0, 1 ); + } + self.pers[ "humiliated" ]++; + self.humiliated = self.pers[ "humiliated" ]; + self thread maps/mp/gametypes/_wager::queuewagerpopup( &"MP_HUMILIATED", 0, &"MP_GUN_PREV_LEVEL", "wm_humiliated" ); + self playlocalsound( game[ "dialog" ][ "wm_humiliation" ] ); + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "wm_humiliated" ); +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( smeansofdeath == "MOD_SUICIDE" || smeansofdeath == "MOD_TRIGGER_HURT" ) + { + self thread demoteplayer(); + return; + } + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + if ( attacker == self ) + { + self thread demoteplayer(); + return; + } + if ( isDefined( attacker.lastpromotiontime ) && ( attacker.lastpromotiontime + 3000 ) > getTime() ) + { + maps/mp/_scoreevents::processscoreevent( "kill_in_3_seconds_gun", attacker, self, sweapon ); + } + if ( smeansofdeath == "MOD_MELEE" ) + { + if ( maps/mp/gametypes/_globallogic::istopscoringplayer( self ) ) + { + maps/mp/_scoreevents::processscoreevent( "knife_leader_gun", attacker, self, sweapon ); + } + else + { + maps/mp/_scoreevents::processscoreevent( "humiliation_gun", attacker, self, sweapon ); + } + attacker playlocalsound( game[ "dialog" ][ "wm_humiliation" ] ); + self thread demoteplayer(); + return; + } + else + { + attacker thread promoteplayer( sweapon ); + } + } +} + +onstartgametype() +{ + level.gungamekillscore = maps/mp/gametypes/_rank::getscoreinfovalue( "kill_gun" ); + registerscorelimit( level.gunprogression.size * level.gungamekillscore, level.gunprogression.size * level.gungamekillscore ); + setdvar( "scr_xpscale", 0 ); + setdvar( "ui_weapon_tiers", level.gunprogression.size ); + makedvarserverinfo( "ui_weapon_tiers", level.gunprogression.size ); + setclientnamemode( "auto_change" ); + setobjectivetext( "allies", &"OBJECTIVES_GUN" ); + setobjectivetext( "axis", &"OBJECTIVES_GUN" ); + if ( level.splitscreen ) + { + setobjectivescoretext( "allies", &"OBJECTIVES_GUN" ); + setobjectivescoretext( "axis", &"OBJECTIVES_GUN" ); + } + else + { + setobjectivescoretext( "allies", &"OBJECTIVES_GUN_SCORE" ); + setobjectivescoretext( "axis", &"OBJECTIVES_GUN_SCORE" ); + } + setobjectivehinttext( "allies", &"OBJECTIVES_GUN_HINT" ); + setobjectivehinttext( "axis", &"OBJECTIVES_GUN_HINT" ); + allowed[ 0 ] = "gun"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 0 ); + level.spawnmaxs = ( 0, 0, 0 ); + newspawns = getentarray( "mp_wager_spawn", "classname" ); + if ( newspawns.size > 0 ) + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_wager_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_wager_spawn" ); + } + else + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_dm_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_dm_spawn" ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.usestartspawns = 0; + level.displayroundendtext = 0; + level.quickmessagetoall = 1; +} + +onspawnplayerunified() +{ + maps/mp/gametypes/_spawning::onspawnplayer_unified(); + self thread infiniteammo(); +} + +onspawnplayer( predictedspawn ) +{ + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( self.pers[ "team" ] ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_dm( spawnpoints ); + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "gun" ); + self thread infiniteammo(); + } +} + +infiniteammo() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + wait 0,1; + weapon = self getcurrentweapon(); + self givemaxammo( weapon ); + } +} + +onwagerawards() +{ + stabs = self maps/mp/gametypes/_globallogic_score::getpersstat( "stabs" ); + if ( !isDefined( stabs ) ) + { + stabs = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", stabs, 0 ); + headshots = self maps/mp/gametypes/_globallogic_score::getpersstat( "headshots" ); + if ( !isDefined( headshots ) ) + { + headshots = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", headshots, 1 ); + bestkillstreak = self maps/mp/gametypes/_globallogic_score::getpersstat( "best_kill_streak" ); + if ( !isDefined( bestkillstreak ) ) + { + bestkillstreak = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", bestkillstreak, 2 ); +} + +onendgame( winningplayer ) +{ + if ( isDefined( winningplayer ) && isplayer( winningplayer ) ) + { + [[ level._setplayerscore ]]( winningplayer, [[ level._getplayerscore ]]( winningplayer ) + level.gungamekillscore ); + } +} diff --git a/patch_mp/maps/mp/gametypes/hq.gsc b/patch_mp/maps/mp/gametypes/hq.gsc new file mode 100644 index 0000000..a0ea0ec --- /dev/null +++ b/patch_mp/maps/mp/gametypes/hq.gsc @@ -0,0 +1,1415 @@ +#include maps/mp/_medals; +#include maps/mp/killstreaks/_supplydrop; +#include maps/mp/gametypes/_weapons; +#include maps/mp/_demo; +#include maps/mp/_popups; +#include maps/mp/_scoreevents; +#include maps/mp/_challenges; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/gametypes/_battlechatter_mp; +#include maps/mp/killstreaks/_rcbomb; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +main() +{ + if ( getDvar( "mapname" ) == "mp_background" ) + { + return; + } + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 1000 ); + registernumlives( 0, 100 ); + registerroundswitch( 0, 9 ); + registerroundwinlimit( 0, 10 ); + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + level.teambased = 1; + level.doprematch = 1; + level.overrideteamscore = 1; + level.scoreroundbased = 1; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.playerspawnedcb = ::koth_playerspawnedcb; + level.onroundswitch = ::onroundswitch; + level.onplayerkilled = ::onplayerkilled; + level.onendgame = ::onendgame; + level.gamemodespawndvars = ::koth_gamemodespawndvars; + precachestring( &"MP_WAITING_FOR_HQ" ); + precachestring( &"MP_HQ_CAPTURED_BY" ); + level.hqautodestroytime = getgametypesetting( "autoDestroyTime" ); + level.hqspawntime = getgametypesetting( "objectiveSpawnTime" ); + level.kothmode = getgametypesetting( "kothMode" ); + level.capturetime = getgametypesetting( "captureTime" ); + level.destroytime = getgametypesetting( "destroyTime" ); + level.delayplayer = getgametypesetting( "delayPlayer" ); + level.randomhqspawn = getgametypesetting( "randomObjectiveLocations" ); + level.maxrespawndelay = getgametypesetting( "timeLimit" ) * 60; + level.iconoffset = vectorScale( ( 0, 0, 0 ), 32 ); + level.onrespawndelay = ::getrespawndelay; + game[ "dialog" ][ "gametype" ] = "hq_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "hchq_start"; + game[ "dialog" ][ "offense_obj" ] = "cap_start"; + game[ "dialog" ][ "defense_obj" ] = "cap_start"; + level.lastdialogtime = 0; + level.radiospawnqueue = []; + if ( !sessionmodeissystemlink() && !sessionmodeisonlinegame() && issplitscreen() ) + { + setscoreboardcolumns( "score", "kills", "captures", "defends", "deaths" ); + } + else + { + setscoreboardcolumns( "score", "kills", "deaths", "captures", "defends" ); + } +} + +updateobjectivehintmessages( defenderteam, defendmessage, attackmessage ) +{ + _a77 = level.teams; + _k77 = getFirstArrayKey( _a77 ); + while ( isDefined( _k77 ) ) + { + team = _a77[ _k77 ]; + if ( defenderteam == team ) + { + game[ "strings" ][ "objective_hint_" + team ] = defendmessage; + } + else + { + game[ "strings" ][ "objective_hint_" + team ] = attackmessage; + } + _k77 = getNextArrayKey( _a77, _k77 ); + } +} + +updateobjectivehintmessage( message ) +{ + _a92 = level.teams; + _k92 = getFirstArrayKey( _a92 ); + while ( isDefined( _k92 ) ) + { + team = _a92[ _k92 ]; + game[ "strings" ][ "objective_hint_" + team ] = message; + _k92 = getNextArrayKey( _a92, _k92 ); + } +} + +getrespawndelay() +{ + self.lowermessageoverride = undefined; + if ( !isDefined( level.radio.gameobject ) ) + { + return undefined; + } + hqowningteam = level.radio.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + if ( self.pers[ "team" ] == hqowningteam ) + { + if ( !isDefined( level.hqdestroytime ) ) + { + timeremaining = level.maxrespawndelay; + } + else + { + timeremaining = ( level.hqdestroytime - getTime() ) / 1000; + } + if ( !level.playerobjectiveheldrespawndelay ) + { + return undefined; + } + if ( level.playerobjectiveheldrespawndelay >= level.hqautodestroytime ) + { + self.lowermessageoverride = &"MP_WAITING_FOR_HQ"; + } + if ( level.delayplayer ) + { + return min( level.spawndelay, timeremaining ); + } + else + { + return ceil( timeremaining ); + } + } +} + +onstartgametype() +{ + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + if ( game[ "switchedsides" ] ) + { + oldattackers = game[ "attackers" ]; + olddefenders = game[ "defenders" ]; + game[ "attackers" ] = olddefenders; + game[ "defenders" ] = oldattackers; + } + maps/mp/gametypes/_globallogic_score::resetteamscores(); + _a146 = level.teams; + _k146 = getFirstArrayKey( _a146 ); + while ( isDefined( _k146 ) ) + { + team = _a146[ _k146 ]; + setobjectivetext( team, &"OBJECTIVES_KOTH" ); + if ( level.splitscreen ) + { + setobjectivescoretext( team, &"OBJECTIVES_HQ" ); + } + else + { + setobjectivescoretext( team, &"OBJECTIVES_HQ_SCORE" ); + } + _k146 = getNextArrayKey( _a146, _k146 ); + } + level.objectivehintpreparehq = &"MP_CONTROL_HQ"; + level.objectivehintcapturehq = &"MP_CAPTURE_HQ"; + level.objectivehintdestroyhq = &"MP_DESTROY_HQ"; + level.objectivehintdefendhq = &"MP_DEFEND_HQ"; + precachestring( level.objectivehintpreparehq ); + precachestring( level.objectivehintcapturehq ); + precachestring( level.objectivehintdestroyhq ); + precachestring( level.objectivehintdefendhq ); + if ( level.kothmode ) + { + level.objectivehintdestroyhq = level.objectivehintcapturehq; + } + if ( level.hqspawntime ) + { + updateobjectivehintmessage( level.objectivehintpreparehq ); + } + else + { + updateobjectivehintmessage( level.objectivehintcapturehq ); + } + setclientnamemode( "auto_change" ); + allowed[ 0 ] = "hq"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 0 ); + level.spawnmaxs = ( 0, 0, 0 ); + _a189 = level.teams; + _k189 = getFirstArrayKey( _a189 ); + while ( isDefined( _k189 ) ) + { + team = _a189[ _k189 ]; + maps/mp/gametypes/_spawnlogic::addspawnpoints( team, "mp_tdm_spawn" ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( maps/mp/gametypes/_spawning::gettdmstartspawnname( team ) ); + _k189 = getNextArrayKey( _a189, _k189 ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.spawn_start = []; + _a200 = level.teams; + _k200 = getFirstArrayKey( _a200 ); + while ( isDefined( _k200 ) ) + { + team = _a200[ _k200 ]; + level.spawn_start[ team ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( maps/mp/gametypes/_spawning::gettdmstartspawnname( team ) ); + _k200 = getNextArrayKey( _a200, _k200 ); + } + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.spawn_all = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_tdm_spawn" ); + if ( !level.spawn_all.size ) + { +/# + println( "^1No mp_tdm_spawn spawnpoints in level!" ); +#/ + maps/mp/gametypes/_callbacksetup::abortlevel(); + return; + } + thread setupradios(); + thread hqmainloop(); +} + +spawn_first_radio( delay ) +{ + if ( level.randomhqspawn == 1 ) + { + level.radio = getnextradiofromqueue(); + } + else + { + level.radio = getfirstradio(); + } + logstring( "radio spawned: (" + level.radio.trigorigin[ 0 ] + "," + level.radio.trigorigin[ 1 ] + "," + level.radio.trigorigin[ 2 ] + ")" ); + level.radio enable_radio_spawn_influencer( 1 ); + return; +} + +spawn_next_radio() +{ + if ( level.randomhqspawn != 0 ) + { + level.radio = getnextradiofromqueue(); + } + else + { + level.radio = getnextradio(); + } + logstring( "radio spawned: (" + level.radio.trigorigin[ 0 ] + "," + level.radio.trigorigin[ 1 ] + "," + level.radio.trigorigin[ 2 ] + ")" ); + level.radio enable_radio_spawn_influencer( 1 ); + return; +} + +hqmainloop() +{ + level endon( "game_ended" ); + level.hqrevealtime = -100000; + hqspawninginstr = &"MP_HQ_AVAILABLE_IN"; + if ( level.kothmode ) + { + hqdestroyedinfriendlystr = &"MP_HQ_DESPAWN_IN"; + hqdestroyedinenemystr = &"MP_HQ_DESPAWN_IN"; + } + else + { + hqdestroyedinfriendlystr = &"MP_HQ_REINFORCEMENTS_IN"; + hqdestroyedinenemystr = &"MP_HQ_DESPAWN_IN"; + } + precachestring( hqspawninginstr ); + precachestring( hqdestroyedinfriendlystr ); + precachestring( hqdestroyedinenemystr ); + precachestring( &"MP_CAPTURING_HQ" ); + precachestring( &"MP_DESTROYING_HQ" ); + spawn_first_radio(); + objective_name = istring( "objective" ); + precachestring( objective_name ); + while ( level.inprematchperiod ) + { + wait 0,05; + } + wait 5; + timerdisplay = []; + _a300 = level.teams; + _k300 = getFirstArrayKey( _a300 ); + while ( isDefined( _k300 ) ) + { + team = _a300[ _k300 ]; + timerdisplay[ team ] = createservertimer( "objective", 1,4, team ); + timerdisplay[ team ] setgamemodeinfopoint(); + timerdisplay[ team ].label = hqspawninginstr; + timerdisplay[ team ].font = "small"; + timerdisplay[ team ].alpha = 0; + timerdisplay[ team ].archived = 0; + timerdisplay[ team ].hidewheninmenu = 1; + timerdisplay[ team ].hidewheninkillcam = 1; + timerdisplay[ team ].showplayerteamhudelemtospectator = 1; + thread hidetimerdisplayongameend( timerdisplay[ team ] ); + _k300 = getNextArrayKey( _a300, _k300 ); + } + while ( 1 ) + { + iprintln( &"MP_HQ_REVEALED" ); + playsoundonplayers( "mp_suitcase_pickup" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "hq_located" ); + level.radio.gameobject maps/mp/gametypes/_gameobjects::setmodelvisibility( 1 ); + level.hqrevealtime = getTime(); + maps/mp/killstreaks/_rcbomb::detonatealliftouchingsphere( level.radio.origin, 75 ); + if ( level.hqspawntime ) + { + level.radio.gameobject maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + level.radio.gameobject maps/mp/gametypes/_gameobjects::setflags( 1 ); + updateobjectivehintmessage( level.objectivehintpreparehq ); + _a345 = level.teams; + _k345 = getFirstArrayKey( _a345 ); + while ( isDefined( _k345 ) ) + { + team = _a345[ _k345 ]; + timerdisplay[ team ].label = hqspawninginstr; + timerdisplay[ team ] settimer( level.hqspawntime ); + timerdisplay[ team ].alpha = 1; + _k345 = getNextArrayKey( _a345, _k345 ); + } + wait level.hqspawntime; + level.radio.gameobject maps/mp/gametypes/_gameobjects::setflags( 0 ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "hq_online" ); + } + _a360 = level.teams; + _k360 = getFirstArrayKey( _a360 ); + while ( isDefined( _k360 ) ) + { + team = _a360[ _k360 ]; + timerdisplay[ team ].alpha = 0; + _k360 = getNextArrayKey( _a360, _k360 ); + } + waittillframeend; + maps/mp/gametypes/_globallogic_audio::leaderdialog( "obj_capture" ); + updateobjectivehintmessage( level.objectivehintcapturehq ); + playsoundonplayers( "mpl_hq_cap_us" ); + level.radio.gameobject maps/mp/gametypes/_gameobjects::enableobject(); + level.radio.gameobject.onupdateuserate = ::onupdateuserate; + level.radio.gameobject maps/mp/gametypes/_gameobjects::allowuse( "any" ); + level.radio.gameobject maps/mp/gametypes/_gameobjects::setusetime( level.capturetime ); + level.radio.gameobject maps/mp/gametypes/_gameobjects::setusetext( &"MP_CAPTURING_HQ" ); + level.radio.gameobject maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + level.radio.gameobject maps/mp/gametypes/_gameobjects::setmodelvisibility( 1 ); + level.radio.gameobject.onuse = ::onradiocapture; + level.radio.gameobject.onbeginuse = ::onbeginuse; + level.radio.gameobject.onenduse = ::onenduse; + level waittill( "hq_captured" ); + ownerteam = level.radio.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + if ( level.hqautodestroytime ) + { + thread destroyhqaftertime( level.hqautodestroytime, ownerteam ); + _a395 = level.teams; + _k395 = getFirstArrayKey( _a395 ); + while ( isDefined( _k395 ) ) + { + team = _a395[ _k395 ]; + timerdisplay[ team ] settimer( level.hqautodestroytime ); + _k395 = getNextArrayKey( _a395, _k395 ); + } + } + else level.hqdestroyedbytimer = 0; + while ( 1 ) + { + ownerteam = level.radio.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + _a409 = level.teams; + _k409 = getFirstArrayKey( _a409 ); + while ( isDefined( _k409 ) ) + { + team = _a409[ _k409 ]; + updateobjectivehintmessages( ownerteam, level.objectivehintdefendhq, level.objectivehintdestroyhq ); + _k409 = getNextArrayKey( _a409, _k409 ); + } + level.radio.gameobject maps/mp/gametypes/_gameobjects::allowuse( "enemy" ); + if ( !level.kothmode ) + { + level.radio.gameobject maps/mp/gametypes/_gameobjects::setusetext( &"MP_DESTROYING_HQ" ); + } + level.radio.gameobject.onuse = ::onradiodestroy; + while ( level.hqautodestroytime ) + { + _a427 = level.teams; + _k427 = getFirstArrayKey( _a427 ); + while ( isDefined( _k427 ) ) + { + team = _a427[ _k427 ]; + if ( team == ownerteam ) + { + timerdisplay[ team ].label = hqdestroyedinfriendlystr; + } + else + { + timerdisplay[ team ].label = hqdestroyedinenemystr; + } + timerdisplay[ team ].alpha = 1; + _k427 = getNextArrayKey( _a427, _k427 ); + } + } + level thread dropallaroundhq(); + level waittill( "hq_destroyed", destroy_team ); + level.radio enable_radio_spawn_influencer( 0 ); + if ( !level.kothmode || level.hqdestroyedbytimer ) + { + break; + } + else + { + thread forcespawnteam( ownerteam ); + if ( isDefined( destroy_team ) ) + { + level.radio.gameobject maps/mp/gametypes/_gameobjects::setownerteam( destroy_team ); + } + } + } + level.radio.gameobject maps/mp/gametypes/_gameobjects::disableobject(); + level.radio.gameobject maps/mp/gametypes/_gameobjects::allowuse( "none" ); + level.radio.gameobject maps/mp/gametypes/_gameobjects::setownerteam( "neutral" ); + level.radio.gameobject maps/mp/gametypes/_gameobjects::setmodelvisibility( 0 ); + level notify( "hq_reset" ); + _a462 = level.teams; + _k462 = getFirstArrayKey( _a462 ); + while ( isDefined( _k462 ) ) + { + team = _a462[ _k462 ]; + timerdisplay[ team ].alpha = 0; + _k462 = getNextArrayKey( _a462, _k462 ); + } + spawn_next_radio(); + wait 0,05; + thread forcespawnteam( ownerteam ); + wait 3; + } +} + +hidetimerdisplayongameend( timerdisplay ) +{ + level waittill( "game_ended" ); + timerdisplay.alpha = 0; +} + +forcespawnteam( team ) +{ + players = level.players; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( !isDefined( player ) ) + { + i++; + continue; + } + else + { + if ( player.pers[ "team" ] == team ) + { + player notify( "force_spawn" ); + wait 0,1; + } + } + i++; + } +} + +onbeginuse( player ) +{ + ownerteam = self maps/mp/gametypes/_gameobjects::getownerteam(); + if ( ownerteam == "neutral" ) + { + player thread maps/mp/gametypes/_battlechatter_mp::gametypespecificbattlechatter( "hq_protect", player.pers[ "team" ] ); + } + else + { + player thread maps/mp/gametypes/_battlechatter_mp::gametypespecificbattlechatter( "hq_attack", player.pers[ "team" ] ); + } +} + +onenduse( team, player, success ) +{ + player notify( "event_ended" ); +} + +onradiocapture( player ) +{ + capture_team = player.pers[ "team" ]; + player logstring( "radio captured" ); + string = &"MP_HQ_CAPTURED_BY"; + level.usestartspawns = 0; + thread give_capture_credit( self.touchlist[ capture_team ], string ); + oldteam = maps/mp/gametypes/_gameobjects::getownerteam(); + self maps/mp/gametypes/_gameobjects::setownerteam( capture_team ); + if ( !level.kothmode ) + { + self maps/mp/gametypes/_gameobjects::setusetime( level.destroytime ); + } + _a550 = level.teams; + _k550 = getFirstArrayKey( _a550 ); + while ( isDefined( _k550 ) ) + { + team = _a550[ _k550 ]; + if ( team == capture_team ) + { + thread printonteamarg( &"MP_HQ_CAPTURED_BY", team, player ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "hq_secured", team ); + thread playsoundonplayers( "mp_war_objective_taken", team ); + } + else + { + thread printonteam( &"MP_HQ_CAPTURED_BY_ENEMY", team ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "hq_enemy_captured", team ); + thread playsoundonplayers( "mp_war_objective_lost", team ); + } + _k550 = getNextArrayKey( _a550, _k550 ); + } + level thread awardhqpoints( capture_team ); + level notify( "hq_captured" ); + player notify( "event_ended" ); +} + +give_capture_credit( touchlist, string ) +{ + time = getTime(); + wait 0,05; + maps/mp/gametypes/_globallogic_utils::waittillslowprocessallowed(); + players = getarraykeys( touchlist ); + i = 0; + while ( i < players.size ) + { + player_from_touchlist = touchlist[ players[ i ] ].player; + player_from_touchlist maps/mp/_challenges::capturedobjective( time ); + maps/mp/_scoreevents::processscoreevent( "hq_secure", player_from_touchlist ); + player_from_touchlist recordgameevent( "capture" ); + level thread maps/mp/_popups::displayteammessagetoall( string, player_from_touchlist ); + if ( isDefined( player_from_touchlist.pers[ "captures" ] ) ) + { + player_from_touchlist.pers[ "captures" ]++; + player_from_touchlist.captures = player_from_touchlist.pers[ "captures" ]; + } + maps/mp/_demo::bookmark( "event", getTime(), player_from_touchlist ); + player_from_touchlist addplayerstatwithgametype( "CAPTURES", 1 ); + i++; + } +} + +dropalltoground( origin, radius, stickyobjectradius ) +{ + physicsexplosionsphere( origin, radius, radius, 0 ); + wait 0,05; + maps/mp/gametypes/_weapons::dropweaponstoground( origin, radius ); + maps/mp/killstreaks/_supplydrop::dropcratestoground( origin, radius ); + level notify( "drop_objects_to_ground" ); +} + +dropallaroundhq( radio ) +{ + origin = level.radio.origin; + level waittill( "hq_reset" ); + dropalltoground( origin, 100, 50 ); +} + +onradiodestroy( firstplayer ) +{ + destroyed_team = firstplayer.pers[ "team" ]; + touchlist = self.touchlist[ destroyed_team ]; + touchlistkeys = getarraykeys( touchlist ); + _a624 = touchlistkeys; + _k624 = getFirstArrayKey( _a624 ); + while ( isDefined( _k624 ) ) + { + index = _a624[ _k624 ]; + player = touchlist[ index ].player; + player logstring( "radio destroyed" ); + maps/mp/_scoreevents::processscoreevent( "hq_destroyed", player ); + player recordgameevent( "destroy" ); + player addplayerstatwithgametype( "DESTRUCTIONS", 1 ); + if ( isDefined( player.pers[ "destructions" ] ) ) + { + player.pers[ "destructions" ]++; + player.destructions = player.pers[ "destructions" ]; + } + _k624 = getNextArrayKey( _a624, _k624 ); + } + destroyteammessage = &"MP_HQ_DESTROYED_BY"; + otherteammessage = &"MP_HQ_DESTROYED_BY_ENEMY"; + if ( level.kothmode ) + { + destroyteammessage = &"MP_HQ_CAPTURED_BY"; + otherteammessage = &"MP_HQ_CAPTURED_BY_ENEMY"; + } + level thread maps/mp/_popups::displayteammessagetoall( destroyteammessage, player ); + _a651 = level.teams; + _k651 = getFirstArrayKey( _a651 ); + while ( isDefined( _k651 ) ) + { + team = _a651[ _k651 ]; + if ( team == destroyed_team ) + { + thread printonteamarg( destroyteammessage, team, player ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "hq_secured", team ); + } + else + { + thread printonteam( otherteammessage, team ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "hq_enemy_destroyed", team ); + } + _k651 = getNextArrayKey( _a651, _k651 ); + } + level notify( "hq_destroyed" ); + if ( level.kothmode ) + { + level thread awardhqpoints( destroyed_team ); + } + player notify( "event_ended" ); +} + +destroyhqaftertime( time, ownerteam ) +{ + level endon( "game_ended" ); + level endon( "hq_reset" ); + level.hqdestroytime = getTime() + ( time * 1000 ); + level.hqdestroyedbytimer = 0; + wait time; + maps/mp/gametypes/_globallogic_audio::leaderdialog( "hq_offline" ); + level.hqdestroyedbytimer = 1; + checkplayercount( ownerteam ); + level notify( "hq_destroyed" ); +} + +checkplayercount( ownerteam ) +{ + lastplayeralive = undefined; + players = level.players; + i = 0; + while ( i < players.size ) + { + if ( players[ i ].team != ownerteam ) + { + i++; + continue; + } + else + { + if ( isalive( players[ i ] ) ) + { + if ( isDefined( lastplayeralive ) ) + { + return; + } + lastplayeralive = players[ i ]; + } + } + i++; + } + if ( isDefined( lastplayeralive ) ) + { + maps/mp/_scoreevents::processscoreevent( "defend_hq_last_man_alive", lastplayeralive ); + } +} + +awardhqpoints( team ) +{ + level endon( "game_ended" ); + level endon( "hq_destroyed" ); + level notify( "awardHQPointsRunning" ); + level endon( "awardHQPointsRunning" ); + seconds = 5; + while ( !level.gameended ) + { + maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( team, seconds ); + index = 0; + while ( index < level.players.size ) + { + player = level.players[ index ]; + if ( player.pers[ "team" ] == team ) + { + } + index++; + } + wait seconds; + } +} + +onspawnplayerunified() +{ + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + spawnpoint = undefined; + if ( !level.usestartspawns ) + { + if ( isDefined( level.radio ) ) + { + if ( isDefined( level.radio.gameobject ) ) + { + radioowningteam = level.radio.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + if ( self.pers[ "team" ] == radioowningteam ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_all, level.radio.gameobject.nearspawns ); + } + else if ( level.spawndelay >= level.radioautomovetime && getTime() > ( level.radiorevealtime + 10000 ) ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_all ); + } + else + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_all, level.radio.gameobject.outerspawns ); + } + } + } + } + if ( !isDefined( spawnpoint ) ) + { + spawnteam = self.pers[ "team" ]; + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_random( level.spawn_start[ spawnteam ] ); + } +/# + assert( isDefined( spawnpoint ) ); +#/ + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "koth" ); + } +} + +koth_playerspawnedcb() +{ + self.lowermessageoverride = undefined; +} + +compareradioindexes( radio_a, radio_b ) +{ + script_index_a = radio_a.script_index; + script_index_b = radio_b.script_index; + if ( !isDefined( script_index_a ) && !isDefined( script_index_b ) ) + { + return 0; + } + if ( !isDefined( script_index_a ) && isDefined( script_index_b ) ) + { +/# + println( "KOTH: Missing script_index on radio at " + radio_a.origin ); +#/ + return 1; + } + if ( isDefined( script_index_a ) && !isDefined( script_index_b ) ) + { +/# + println( "KOTH: Missing script_index on radio at " + radio_b.origin ); +#/ + return 0; + } + if ( script_index_a > script_index_b ) + { + return 1; + } + return 0; +} + +getradioarray() +{ + radios = getentarray( "hq_hardpoint", "targetname" ); + if ( !isDefined( radios ) ) + { + return undefined; + } + swapped = 1; + n = radios.size; + while ( swapped ) + { + swapped = 0; + i = 0; + while ( i < ( n - 1 ) ) + { + if ( compareradioindexes( radios[ i ], radios[ i + 1 ] ) ) + { + temp = radios[ i ]; + radios[ i ] = radios[ i + 1 ]; + radios[ i + 1 ] = temp; + swapped = 1; + } + i++; + } + n--; + + } + return radios; +} + +setupradios() +{ + maperrors = []; + radios = getradioarray(); + if ( radios.size < 2 ) + { + maperrors[ maperrors.size ] = "There are not at least 2 entities with targetname "radio""; + } + trigs = getentarray( "radiotrigger", "targetname" ); + i = 0; + while ( i < radios.size ) + { + errored = 0; + radio = radios[ i ]; + radio.trig = undefined; + j = 0; + while ( j < trigs.size ) + { + if ( radio istouching( trigs[ j ] ) ) + { + if ( isDefined( radio.trig ) ) + { + maperrors[ maperrors.size ] = "Radio at " + radio.origin + " is touching more than one "radiotrigger" trigger"; + errored = 1; + break; + } + else radio.trig = trigs[ j ]; + break; + } + else + { + j++; + } + } + if ( !isDefined( radio.trig ) ) + { + if ( !errored ) + { + maperrors[ maperrors.size ] = "Radio at " + radio.origin + " is not inside any "radiotrigger" trigger"; + i++; + continue; + } + } + else + { +/# + assert( !errored ); +#/ + radio.trigorigin = radio.trig.origin; + visuals = []; + visuals[ 0 ] = radio; + othervisuals = getentarray( radio.target, "targetname" ); + j = 0; + while ( j < othervisuals.size ) + { + visuals[ visuals.size ] = othervisuals[ j ]; + j++; + } + objective_name = istring( "objective" ); + precachestring( objective_name ); + radio setupnodes(); + radio.gameobject = maps/mp/gametypes/_gameobjects::createuseobject( "neutral", radio.trig, visuals, radio.origin - radio.trigorigin, objective_name ); + radio.gameobject maps/mp/gametypes/_gameobjects::disableobject(); + radio.gameobject maps/mp/gametypes/_gameobjects::setmodelvisibility( 0 ); + radio.trig.useobj = radio.gameobject; + radio setupnearbyspawns(); + radio createradiospawninfluencer(); + } + i++; + } + if ( maperrors.size > 0 ) + { +/# + println( "^1------------ Map Errors ------------" ); + i = 0; + while ( i < maperrors.size ) + { + println( maperrors[ i ] ); + i++; + } + println( "^1------------------------------------" ); + maps/mp/_utility::error( "Map errors. See above" ); +#/ + maps/mp/gametypes/_callbacksetup::abortlevel(); + return; + } + level.radios = radios; + level.prevradio = undefined; + level.prevradio2 = undefined; + return 1; +} + +setupnearbyspawns() +{ + spawns = level.spawn_all; + i = 0; + while ( i < spawns.size ) + { + spawns[ i ].distsq = distancesquared( spawns[ i ].origin, self.origin ); + i++; + } + i = 1; + while ( i < spawns.size ) + { + thespawn = spawns[ i ]; + j = i - 1; + while ( j >= 0 && thespawn.distsq < spawns[ j ].distsq ) + { + spawns[ j + 1 ] = spawns[ j ]; + j--; + + } + spawns[ j + 1 ] = thespawn; + i++; + } + first = []; + second = []; + third = []; + outer = []; + thirdsize = spawns.size / 3; + i = 0; + while ( i <= thirdsize ) + { + first[ first.size ] = spawns[ i ]; + i++; + } + while ( i < spawns.size ) + { + outer[ outer.size ] = spawns[ i ]; + if ( i <= ( thirdsize * 2 ) ) + { + second[ second.size ] = spawns[ i ]; + i++; + continue; + } + else + { + third[ third.size ] = spawns[ i ]; + } + i++; + } + self.gameobject.nearspawns = first; + self.gameobject.midspawns = second; + self.gameobject.farspawns = third; + self.gameobject.outerspawns = outer; +} + +setupnodes() +{ + self.nodes = []; + temp = spawn( "script_model", ( 0, 0, 0 ) ); + maxs = self.trig getpointinbounds( 1, 1, 1 ); + self.node_radius = distance( self.trig.origin, maxs ); + nodes = getnodesinradius( self.trig.origin, self.node_radius, 0, self.node_radius ); + _a1009 = nodes; + _k1009 = getFirstArrayKey( _a1009 ); + while ( isDefined( _k1009 ) ) + { + node = _a1009[ _k1009 ]; + temp.origin = node.origin; + if ( temp istouching( self.trig ) ) + { + self.nodes[ self.nodes.size ] = node; + } + _k1009 = getNextArrayKey( _a1009, _k1009 ); + } +/# + assert( self.nodes.size ); +#/ + temp delete(); +} + +getfirstradio() +{ + radio = level.radios[ 0 ]; + level.prevradio2 = level.prevradio; + level.prevradio = radio; + level.prevradioindex = 0; + shuffleradios(); + arrayremovevalue( level.radiospawnqueue, radio ); + return radio; +} + +getnextradio() +{ + nextradioindex = ( level.prevradioindex + 1 ) % level.radios.size; + radio = level.radios[ nextradioindex ]; + level.prevradio2 = level.prevradio; + level.prevradio = radio; + level.prevradioindex = nextradioindex; + return radio; +} + +pickrandomradiotospawn() +{ + level.prevradioindex = randomint( level.radios.size ); + radio = level.radios[ level.prevradioindex ]; + level.prevradio2 = level.prevradio; + level.prevradio = radio; + return radio; +} + +shuffleradios() +{ + level.radiospawnqueue = []; + spawnqueue = arraycopy( level.radios ); + total_left = spawnqueue.size; + while ( total_left > 0 ) + { + index = randomint( total_left ); + valid_radios = 0; + radio = 0; + while ( radio < level.radios.size ) + { + if ( !isDefined( spawnqueue[ radio ] ) ) + { + radio++; + continue; + } + else if ( valid_radios == index ) + { + if ( level.radiospawnqueue.size == 0 && isDefined( level.radio ) && level.radio == spawnqueue[ radio ] ) + { + radio++; + continue; + } + else + { + level.radiospawnqueue[ level.radiospawnqueue.size ] = spawnqueue[ radio ]; + total_left--; + continue; + } + else + { + valid_radios++; + } + radio++; + } + } + total_left--; + + } +} + +getnextradiofromqueue() +{ + if ( level.radiospawnqueue.size == 0 ) + { + shuffleradios(); + } +/# + assert( level.radiospawnqueue.size > 0 ); +#/ + next_radio = level.radiospawnqueue[ 0 ]; + arrayremoveindex( level.radiospawnqueue, 0 ); + return next_radio; +} + +getcountofteamswithplayers( num ) +{ + has_players = 0; + _a1113 = level.teams; + _k1113 = getFirstArrayKey( _a1113 ); + while ( isDefined( _k1113 ) ) + { + team = _a1113[ _k1113 ]; + if ( num[ team ] > 0 ) + { + has_players++; + } + _k1113 = getNextArrayKey( _a1113, _k1113 ); + } + return has_players; +} + +getpointcost( avgpos, origin ) +{ + avg_distance = 0; + total_error = 0; + distances = []; + _a1128 = avgpos; + team = getFirstArrayKey( _a1128 ); + while ( isDefined( team ) ) + { + position = _a1128[ team ]; + distances[ team ] = distance( origin, avgpos[ team ] ); + avg_distance += distances[ team ]; + team = getNextArrayKey( _a1128, team ); + } + avg_distance /= distances.size; + _a1136 = distances; + team = getFirstArrayKey( _a1136 ); + while ( isDefined( team ) ) + { + dist = _a1136[ team ]; + err = distances[ team ] - avg_distance; + total_error += err * err; + team = getNextArrayKey( _a1136, team ); + } + return total_error; +} + +pickradiotospawn() +{ + _a1151 = level.teams; + _k1151 = getFirstArrayKey( _a1151 ); + while ( isDefined( _k1151 ) ) + { + team = _a1151[ _k1151 ]; + avgpos[ team ] = ( 0, 0, 0 ); + num[ team ] = 0; + _k1151 = getNextArrayKey( _a1151, _k1151 ); + } + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isalive( player ) ) + { + avgpos[ player.pers[ "team" ] ] += player.origin; + num[ player.pers[ "team" ] ]++; + } + i++; + } + if ( getcountofteamswithplayers( num ) <= 1 ) + { + radio = level.radios[ randomint( level.radios.size ) ]; + while ( isDefined( level.prevradio ) && radio == level.prevradio ) + { + radio = level.radios[ randomint( level.radios.size ) ]; + } + level.prevradio2 = level.prevradio; + level.prevradio = radio; + return radio; + } + _a1179 = level.teams; + _k1179 = getFirstArrayKey( _a1179 ); + while ( isDefined( _k1179 ) ) + { + team = _a1179[ _k1179 ]; + if ( num[ team ] == 0 ) + { + } + else + { + avgpos[ team ] /= num[ team ]; + } + _k1179 = getNextArrayKey( _a1179, _k1179 ); + } + bestradio = undefined; + lowestcost = undefined; + i = 0; + while ( i < level.radios.size ) + { + radio = level.radios[ i ]; + cost = getpointcost( avgpos, radio.origin ); + if ( isDefined( level.prevradio ) && radio == level.prevradio ) + { + i++; + continue; + } + else + { + if ( isDefined( level.prevradio2 ) && radio == level.prevradio2 ) + { + if ( level.radios.size > 2 ) + { + i++; + continue; + } + else cost += 262144; + } + if ( !isDefined( lowestcost ) || cost < lowestcost ) + { + lowestcost = cost; + bestradio = radio; + } + } + i++; + } +/# + assert( isDefined( bestradio ) ); +#/ + level.prevradio2 = level.prevradio; + level.prevradio = bestradio; + return bestradio; +} + +onroundswitch() +{ + game[ "switchedsides" ] = !game[ "switchedsides" ]; +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( isplayer( attacker ) && !self.touchtriggers.size || !attacker.touchtriggers.size && attacker.pers[ "team" ] == self.pers[ "team" ] ) + { + return; + } + medalgiven = 0; + scoreeventprocessed = 0; + if ( attacker.touchtriggers.size ) + { + triggerids = getarraykeys( attacker.touchtriggers ); + ownerteam = attacker.touchtriggers[ triggerids[ 0 ] ].useobj.ownerteam; + team = attacker.pers[ "team" ]; + if ( team == ownerteam || ownerteam == "neutral" ) + { + if ( !medalgiven ) + { + if ( isDefined( attacker.pers[ "defends" ] ) ) + { + attacker.pers[ "defends" ]++; + attacker.defends = attacker.pers[ "defends" ]; + } + attacker maps/mp/_medals::defenseglobalcount(); + medalgiven = 1; + attacker addplayerstatwithgametype( "DEFENDS", 1 ); + attacker recordgameevent( "return" ); + } + attacker maps/mp/_challenges::killedzoneattacker( sweapon ); + if ( team != ownerteam ) + { + maps/mp/_scoreevents::processscoreevent( "kill_enemy_while_capping_hq", attacker, undefined, sweapon ); + } + else + { + maps/mp/_scoreevents::processscoreevent( "killed_attacker", attacker, undefined, sweapon ); + } + self recordkillmodifier( "assaulting" ); + scoreeventprocessed = 1; + } + else + { + if ( !medalgiven ) + { + attacker maps/mp/_medals::offenseglobalcount(); + medalgiven = 1; + attacker addplayerstatwithgametype( "OFFENDS", 1 ); + } + maps/mp/_scoreevents::processscoreevent( "kill_enemy_while_capping_hq", attacker, undefined, sweapon ); + self recordkillmodifier( "defending" ); + scoreeventprocessed = 1; + } + } + if ( self.touchtriggers.size ) + { + triggerids = getarraykeys( self.touchtriggers ); + ownerteam = self.touchtriggers[ triggerids[ 0 ] ].useobj.ownerteam; + team = self.pers[ "team" ]; + if ( team == ownerteam ) + { + if ( !medalgiven ) + { + attacker maps/mp/_medals::offenseglobalcount(); + attacker addplayerstatwithgametype( "OFFENDS", 1 ); + medalgiven = 1; + } + if ( !scoreeventprocessed ) + { + maps/mp/_scoreevents::processscoreevent( "killed_defender", attacker, undefined, sweapon ); + self recordkillmodifier( "defending" ); + scoreeventprocessed = 1; + } + } + else + { + if ( !medalgiven ) + { + if ( isDefined( attacker.pers[ "defends" ] ) ) + { + attacker.pers[ "defends" ]++; + attacker.defends = attacker.pers[ "defends" ]; + } + attacker maps/mp/_medals::defenseglobalcount(); + medalgiven = 1; + attacker addplayerstatwithgametype( "DEFENDS", 1 ); + attacker recordgameevent( "return" ); + } + if ( !scoreeventprocessed ) + { + attacker maps/mp/_challenges::killedzoneattacker( sweapon ); + maps/mp/_scoreevents::processscoreevent( "killed_attacker", attacker, undefined, sweapon ); + self recordkillmodifier( "assaulting" ); + scoreeventprocessed = 1; + } + } + if ( scoreeventprocessed == 1 ) + { + attacker killwhilecontesting( self.touchtriggers[ triggerids[ 0 ] ].useobj ); + } + } +} + +killwhilecontesting( radio ) +{ + self notify( "killWhileContesting" ); + self endon( "killWhileContesting" ); + self endon( "disconnect" ); + killtime = getTime(); + playerteam = self.pers[ "team" ]; + if ( !isDefined( self.clearenemycount ) ) + { + self.clearenemycount = 0; + } + self.clearenemycount++; + radio waittill( "state_change" ); + if ( playerteam != self.pers[ "team" ] || isDefined( self.spawntime ) && killtime < self.spawntime ) + { + self.clearenemycount = 0; + return; + } + if ( radio.ownerteam != playerteam && radio.ownerteam != "neutral" ) + { + self.clearenemycount = 0; + return; + } + if ( self.clearenemycount >= 2 && ( killtime + 200 ) > getTime() ) + { + maps/mp/_scoreevents::processscoreevent( "clear_2_attackers", self ); + } + self.clearenemycount = 0; +} + +onendgame( winningteam ) +{ + i = 0; + while ( i < level.radios.size ) + { + level.radios[ i ].gameobject maps/mp/gametypes/_gameobjects::allowuse( "none" ); + i++; + } +} + +createradiospawninfluencer() +{ + hq_objective_influencer_score = level.spawnsystem.hq_objective_influencer_score; + hq_objective_influencer_score_curve = level.spawnsystem.hq_objective_influencer_score_curve; + hq_objective_influencer_radius = level.spawnsystem.hq_objective_influencer_radius; + hq_objective_influencer_inner_score = level.spawnsystem.hq_objective_influencer_inner_score; + hq_objective_influencer_inner_score_curve = level.spawnsystem.hq_objective_influencer_inner_score_curve; + hq_objective_influencer_inner_radius = level.spawnsystem.hq_objective_influencer_inner_radius; + self.spawn_influencer = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.gameobject.curorigin, hq_objective_influencer_radius, hq_objective_influencer_score, 0, "hq_objective,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( hq_objective_influencer_score_curve ) ); + self.spawn_influencer_inner = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.gameobject.curorigin, hq_objective_influencer_inner_radius, hq_objective_influencer_inner_score, 0, "hq_objective_inner,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( hq_objective_influencer_inner_score_curve ) ); + self enable_radio_spawn_influencer( 0 ); +} + +enable_radio_spawn_influencer( enabled ) +{ + if ( isDefined( self.spawn_influencer ) ) + { + enableinfluencer( self.spawn_influencer, enabled ); + enableinfluencer( self.spawn_influencer_inner, enabled ); + } +} + +koth_gamemodespawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.hq_objective_influencer_score = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_score", "200", reset_dvars ); + ss.hq_objective_influencer_score_curve = set_dvar_if_unset( "scr_spawn_hq_objective_influencer_score_curve", "linear", reset_dvars ); + ss.hq_objective_influencer_radius = 4000; + ss.hq_objective_influencer_inner_score = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_score", "-600", reset_dvars ); + ss.hq_objective_influencer_inner_score_curve = "constant"; + ss.hq_objective_influencer_inner_radius = set_dvar_float_if_unset( "scr_spawn_hq_objective_influencer_inner_radius", "2000", reset_dvars ); + ss.hq_initial_spawns_influencer_score = set_dvar_float_if_unset( "scr_spawn_hq_initial_spawns_influencer_score", "200", reset_dvars ); + ss.hq_initial_spawns_influencer_score_curve = set_dvar_if_unset( "scr_spawn_hq_initial_spawns_influencer_score_curve", "linear", reset_dvars ); + ss.hq_initial_spawns_influencer_radius = set_dvar_float_if_unset( "scr_spawn_hq_initial_spawns_influencer_radius", "" + ( 10 * get_player_height() ), reset_dvars ); +} + +onupdateuserate() +{ + if ( !isDefined( self.currentcontendercount ) ) + { + self.currentcontendercount = 0; + } + numothers = getnumtouchingexceptteam( self.ownerteam ); + numowners = self.numtouching[ self.ownerteam ]; + previousstate = self.currentcontendercount; + if ( numothers == 0 && numowners == 0 ) + { + self.currentcontendercount = 0; + } + else + { + if ( self.ownerteam == "neutral" ) + { + numotherclaim = getnumtouchingexceptteam( self.claimteam ); + if ( numotherclaim > 0 ) + { + self.currentcontendercount = 2; + } + else + { + self.currentcontendercount = 1; + } + } + else if ( numothers > 0 ) + { + self.currentcontendercount = 1; + } + else + { + self.currentcontendercount = 0; + } + } + if ( self.currentcontendercount != previousstate ) + { + self notify( "state_change" ); + } +} diff --git a/patch_mp/maps/mp/gametypes/koth.gsc b/patch_mp/maps/mp/gametypes/koth.gsc new file mode 100644 index 0000000..f26db95 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/koth.gsc @@ -0,0 +1,1573 @@ +#include maps/mp/_medals; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/_demo; +#include maps/mp/_popups; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/_challenges; +#include maps/mp/gametypes/_battlechatter_mp; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + if ( getDvar( "mapname" ) == "mp_background" ) + { + return; + } + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 1000 ); + registernumlives( 0, 100 ); + registerroundswitch( 0, 9 ); + registerroundwinlimit( 0, 10 ); + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + level.teambased = 1; + level.doprematch = 1; + level.overrideteamscore = 1; + level.scoreroundbased = 1; + level.kothstarttime = 0; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.playerspawnedcb = ::koth_playerspawnedcb; + level.onroundswitch = ::onroundswitch; + level.onplayerkilled = ::onplayerkilled; + level.onendgame = ::onendgame; + level.gamemodespawndvars = ::koth_gamemodespawndvars; + loadfx( "maps/mp_maps/fx_mp_koth_marker_neutral_1" ); + loadfx( "maps/mp_maps/fx_mp_koth_marker_neutral_wndw" ); + precachestring( &"MP_WAITING_FOR_HQ" ); + precachestring( &"MP_KOTH_CAPTURED_BY" ); + precachestring( &"MP_KOTH_CAPTURED_BY_ENEMY" ); + precachestring( &"MP_KOTH_MOVING_IN" ); + precachestring( &"MP_CAPTURING_OBJECTIVE" ); + precachestring( &"MP_KOTH_CONTESTED_BY_ENEMY" ); + precachestring( &"MP_KOTH_AVAILABLE_IN" ); + registerclientfield( "world", "hardpoint", 1, 5, "int" ); + level.zoneautomovetime = getgametypesetting( "autoDestroyTime" ); + level.zonespawntime = getgametypesetting( "objectiveSpawnTime" ); + level.kothmode = getgametypesetting( "kothMode" ); + level.capturetime = getgametypesetting( "captureTime" ); + level.destroytime = getgametypesetting( "destroyTime" ); + level.delayplayer = getgametypesetting( "delayPlayer" ); + level.randomzonespawn = getgametypesetting( "randomObjectiveLocations" ); + level.scoreperplayer = getgametypesetting( "scorePerPlayer" ); + level.iconoffset = vectorScale( ( 0, 0, 0 ), 32 ); + level.onrespawndelay = ::getrespawndelay; + game[ "dialog" ][ "gametype" ] = "koth_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "koth_start"; + game[ "dialog" ][ "offense_obj" ] = "cap_start"; + game[ "dialog" ][ "defense_obj" ] = "cap_start"; + game[ "objective_gained_sound" ] = "mpl_flagcapture_sting_friend"; + game[ "objective_lost_sound" ] = "mpl_flagcapture_sting_enemy"; + game[ "objective_contested_sound" ] = "mpl_flagreturn_sting"; + level.lastdialogtime = 0; + level.zonespawnqueue = []; + if ( !sessionmodeissystemlink() && !sessionmodeisonlinegame() && issplitscreen() ) + { + setscoreboardcolumns( "score", "kills", "captures", "defends", "deaths" ); + } + else + { + setscoreboardcolumns( "score", "kills", "deaths", "captures", "defends" ); + } + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "gamemode_objective", 0 ); +/# + trigs = getentarray( "radiotrigger", "targetname" ); + _a101 = trigs; + _k101 = getFirstArrayKey( _a101 ); + while ( isDefined( _k101 ) ) + { + trig = _a101[ _k101 ]; + trig delete(); + _k101 = getNextArrayKey( _a101, _k101 ); +#/ + } +} + +updateobjectivehintmessages( defenderteam, defendmessage, attackmessage ) +{ + _a111 = level.teams; + _k111 = getFirstArrayKey( _a111 ); + while ( isDefined( _k111 ) ) + { + team = _a111[ _k111 ]; + if ( defenderteam == team ) + { + game[ "strings" ][ "objective_hint_" + team ] = defendmessage; + } + else + { + game[ "strings" ][ "objective_hint_" + team ] = attackmessage; + } + _k111 = getNextArrayKey( _a111, _k111 ); + } +} + +updateobjectivehintmessage( message ) +{ + _a126 = level.teams; + _k126 = getFirstArrayKey( _a126 ); + while ( isDefined( _k126 ) ) + { + team = _a126[ _k126 ]; + game[ "strings" ][ "objective_hint_" + team ] = message; + _k126 = getNextArrayKey( _a126, _k126 ); + } +} + +getrespawndelay() +{ + self.lowermessageoverride = undefined; + if ( !isDefined( level.zone.gameobject ) ) + { + return undefined; + } + zoneowningteam = level.zone.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + if ( self.pers[ "team" ] == zoneowningteam ) + { + if ( !isDefined( level.zonemovetime ) ) + { + return undefined; + } + timeremaining = ( level.zonemovetime - getTime() ) / 1000; + if ( !level.playerobjectiveheldrespawndelay ) + { + return undefined; + } + if ( level.playerobjectiveheldrespawndelay >= level.zoneautomovetime ) + { + self.lowermessageoverride = &"MP_WAITING_FOR_HQ"; + } + if ( level.delayplayer ) + { + return min( level.spawndelay, timeremaining ); + } + else + { + return ceil( timeremaining ); + } + } +} + +onstartgametype() +{ + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + if ( game[ "switchedsides" ] ) + { + oldattackers = game[ "attackers" ]; + olddefenders = game[ "defenders" ]; + game[ "attackers" ] = olddefenders; + game[ "defenders" ] = oldattackers; + } + maps/mp/gametypes/_globallogic_score::resetteamscores(); + _a180 = level.teams; + _k180 = getFirstArrayKey( _a180 ); + while ( isDefined( _k180 ) ) + { + team = _a180[ _k180 ]; + setobjectivetext( team, &"OBJECTIVES_KOTH" ); + if ( level.splitscreen ) + { + setobjectivescoretext( team, &"OBJECTIVES_KOTH" ); + } + else + { + setobjectivescoretext( team, &"OBJECTIVES_KOTH_SCORE" ); + } + _k180 = getNextArrayKey( _a180, _k180 ); + } + level.objectivehintpreparezone = &"MP_CONTROL_KOTH"; + level.objectivehintcapturezone = &"MP_CAPTURE_KOTH"; + level.objectivehintdefendhq = &"MP_DEFEND_KOTH"; + precachestring( level.objectivehintpreparezone ); + precachestring( level.objectivehintcapturezone ); + precachestring( level.objectivehintdefendhq ); + if ( level.zonespawntime ) + { + updateobjectivehintmessage( level.objectivehintpreparezone ); + } + else + { + updateobjectivehintmessage( level.objectivehintcapturezone ); + } + setclientnamemode( "auto_change" ); + allowed[ 0 ] = "koth"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 0 ); + level.spawnmaxs = ( 0, 0, 0 ); + _a218 = level.teams; + _k218 = getFirstArrayKey( _a218 ); + while ( isDefined( _k218 ) ) + { + team = _a218[ _k218 ]; + maps/mp/gametypes/_spawnlogic::addspawnpoints( team, "mp_tdm_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( team, "mp_multi_team_spawn" ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( maps/mp/gametypes/_spawning::gettdmstartspawnname( team ) ); + _k218 = getNextArrayKey( _a218, _k218 ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.spawn_start = []; + _a230 = level.teams; + _k230 = getFirstArrayKey( _a230 ); + while ( isDefined( _k230 ) ) + { + team = _a230[ _k230 ]; + level.spawn_start[ team ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( maps/mp/gametypes/_spawning::gettdmstartspawnname( team ) ); + _k230 = getNextArrayKey( _a230, _k230 ); + } + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.spawn_all = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_tdm_spawn" ); + if ( !level.spawn_all.size ) + { +/# + println( "^1No mp_tdm_spawn spawnpoints in level!" ); +#/ + maps/mp/gametypes/_callbacksetup::abortlevel(); + return; + } + thread setupzones(); + updategametypedvars(); + thread kothmainloop(); +} + +updategametypedvars() +{ + level.playercapturelpm = getgametypesetting( "maxPlayerEventsPerMinute" ); +} + +spawn_first_zone( delay ) +{ + if ( level.randomzonespawn == 1 ) + { + level.zone = getnextzonefromqueue(); + } + else + { + level.zone = getfirstzone(); + } + if ( isDefined( level.zone ) ) + { + logstring( "zone spawned: (" + level.zone.trigorigin[ 0 ] + "," + level.zone.trigorigin[ 1 ] + "," + level.zone.trigorigin[ 2 ] + ")" ); + level.zone enable_zone_spawn_influencer( 1 ); + } + level.zone.gameobject.trigger allowtacticalinsertion( 0 ); + return; +} + +spawn_next_zone() +{ + level.zone.gameobject.trigger allowtacticalinsertion( 1 ); + if ( level.randomzonespawn != 0 ) + { + level.zone = getnextzonefromqueue(); + } + else + { + level.zone = getnextzone(); + } + if ( isDefined( level.zone ) ) + { + logstring( "zone spawned: (" + level.zone.trigorigin[ 0 ] + "," + level.zone.trigorigin[ 1 ] + "," + level.zone.trigorigin[ 2 ] + ")" ); + level.zone enable_zone_spawn_influencer( 1 ); + } + level.zone.gameobject.trigger allowtacticalinsertion( 0 ); + return; +} + +getnumtouching() +{ + numtouching = 0; + _a318 = level.teams; + _k318 = getFirstArrayKey( _a318 ); + while ( isDefined( _k318 ) ) + { + team = _a318[ _k318 ]; + numtouching += self.numtouching[ team ]; + _k318 = getNextArrayKey( _a318, _k318 ); + } + return numtouching; +} + +togglezoneeffects( enabled ) +{ + index = 0; + if ( enabled ) + { + index = self.script_index; + } + level setclientfield( "hardpoint", index ); +} + +kothcaptureloop() +{ + level endon( "game_ended" ); + level endon( "zone_moved" ); + level.kothstarttime = getTime(); + while ( 1 ) + { + level.zone.gameobject maps/mp/gametypes/_gameobjects::allowuse( "any" ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::setusetime( level.capturetime ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::setusetext( &"MP_CAPTURING_OBJECTIVE" ); + numtouching = level.zone.gameobject getnumtouching(); + level.zone.gameobject maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::setmodelvisibility( 1 ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::mustmaintainclaim( 0 ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::cancontestclaim( 1 ); + level.zone.gameobject.onuse = ::onzonecapture; + level.zone.gameobject.onbeginuse = ::onbeginuse; + level.zone.gameobject.onenduse = ::onenduse; + level.zone togglezoneeffects( 1 ); + msg = level waittill_any_return( "zone_captured", "zone_destroyed" ); + while ( msg == "zone_destroyed" ) + { + continue; + } + ownerteam = level.zone.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + _a371 = level.teams; + _k371 = getFirstArrayKey( _a371 ); + while ( isDefined( _k371 ) ) + { + team = _a371[ _k371 ]; + updateobjectivehintmessages( ownerteam, level.objectivehintdefendhq, level.objectivehintcapturezone ); + _k371 = getNextArrayKey( _a371, _k371 ); + } + level.zone.gameobject maps/mp/gametypes/_gameobjects::allowuse( "none" ); + level.zone.gameobject.onuse = undefined; + level.zone.gameobject.onunoccupied = ::onzoneunoccupied; + level.zone.gameobject.oncontested = ::onzonecontested; + level.zone.gameobject.onuncontested = ::onzoneuncontested; + level waittill( "zone_destroyed", destroy_team ); + if ( !level.kothmode || level.zonedestroyedbytimer ) + { + return; + } + else + { + thread forcespawnteam( ownerteam ); + if ( isDefined( destroy_team ) ) + { + level.zone.gameobject maps/mp/gametypes/_gameobjects::setownerteam( destroy_team ); + continue; + } + else + { + level.zone.gameobject maps/mp/gametypes/_gameobjects::setownerteam( "none" ); + } + } + } +} + +kothmainloop() +{ + level endon( "game_ended" ); + level.zonerevealtime = -100000; + zonespawninginstr = &"MP_KOTH_AVAILABLE_IN"; + if ( level.kothmode ) + { + zonedestroyedinfriendlystr = &"MP_HQ_DESPAWN_IN"; + zonedestroyedinenemystr = &"MP_KOTH_MOVING_IN"; + } + else + { + zonedestroyedinfriendlystr = &"MP_HQ_REINFORCEMENTS_IN"; + zonedestroyedinenemystr = &"MP_HQ_DESPAWN_IN"; + } + precachestring( zonespawninginstr ); + precachestring( zonedestroyedinfriendlystr ); + precachestring( zonedestroyedinenemystr ); + precachestring( &"MP_CAPTURING_HQ" ); + precachestring( &"MP_DESTROYING_HQ" ); + objective_name = istring( "objective" ); + precachestring( objective_name ); + spawn_first_zone(); + while ( level.inprematchperiod ) + { + wait 0,05; + } + wait 5; + timerdisplay = []; + _a436 = level.teams; + _k436 = getFirstArrayKey( _a436 ); + while ( isDefined( _k436 ) ) + { + team = _a436[ _k436 ]; + timerdisplay[ team ] = createservertimer( "objective", 1,4, team ); + timerdisplay[ team ] setgamemodeinfopoint(); + timerdisplay[ team ].label = zonespawninginstr; + timerdisplay[ team ].font = "extrasmall"; + timerdisplay[ team ].alpha = 0; + timerdisplay[ team ].archived = 0; + timerdisplay[ team ].hidewheninmenu = 1; + timerdisplay[ team ].hidewheninkillcam = 1; + timerdisplay[ team ].showplayerteamhudelemtospectator = 1; + thread hidetimerdisplayongameend( timerdisplay[ team ] ); + _k436 = getNextArrayKey( _a436, _k436 ); + } + while ( 1 ) + { + playsoundonplayers( "mp_suitcase_pickup" ); + maps/mp/gametypes/_globallogic_audio::flushgroupdialog( "gamemode_objective" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "koth_located" ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::setmodelvisibility( 1 ); + level.zonerevealtime = getTime(); + if ( level.zonespawntime ) + { + level.zone.gameobject maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::setflags( 1 ); + updateobjectivehintmessage( level.objectivehintpreparezone ); + _a468 = level.teams; + _k468 = getFirstArrayKey( _a468 ); + while ( isDefined( _k468 ) ) + { + team = _a468[ _k468 ]; + timerdisplay[ team ].label = zonespawninginstr; + timerdisplay[ team ] settimer( level.zonespawntime ); + timerdisplay[ team ].alpha = 1; + _k468 = getNextArrayKey( _a468, _k468 ); + } + wait level.zonespawntime; + level.zone.gameobject maps/mp/gametypes/_gameobjects::setflags( 0 ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "koth_online" ); + } + _a481 = level.teams; + _k481 = getFirstArrayKey( _a481 ); + while ( isDefined( _k481 ) ) + { + team = _a481[ _k481 ]; + timerdisplay[ team ].alpha = 0; + _k481 = getNextArrayKey( _a481, _k481 ); + } + waittillframeend; + maps/mp/gametypes/_globallogic_audio::leaderdialog( "obj_capture", undefined, "gamemode_objective" ); + updateobjectivehintmessage( level.objectivehintcapturezone ); + playsoundonplayers( "mpl_hq_cap_us" ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::enableobject(); + level.zone.gameobject.capturecount = 0; + if ( level.zoneautomovetime ) + { + thread movezoneaftertime( level.zoneautomovetime ); + _a498 = level.teams; + _k498 = getFirstArrayKey( _a498 ); + while ( isDefined( _k498 ) ) + { + team = _a498[ _k498 ]; + timerdisplay[ team ] settimer( level.zoneautomovetime ); + _k498 = getNextArrayKey( _a498, _k498 ); + } + _a503 = level.teams; + _k503 = getFirstArrayKey( _a503 ); + while ( isDefined( _k503 ) ) + { + team = _a503[ _k503 ]; + timerdisplay[ team ].label = zonedestroyedinenemystr; + timerdisplay[ team ].alpha = 1; + _k503 = getNextArrayKey( _a503, _k503 ); + } + } + else level.zonedestroyedbytimer = 0; + kothcaptureloop(); + ownerteam = level.zone.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + if ( level.zone.gameobject.capturecount == 1 ) + { + touchlist = []; + touchkeys = getarraykeys( level.zone.gameobject.touchlist[ ownerteam ] ); + i = 0; + while ( i < touchkeys.size ) + { + touchlist[ touchkeys[ i ] ] = level.zone.gameobject.touchlist[ ownerteam ][ touchkeys[ i ] ]; + i++; + } + thread give_held_credit( touchlist ); + } + level.zone enable_zone_spawn_influencer( 0 ); + level.zone.gameobject.lastcaptureteam = undefined; + level.zone.gameobject maps/mp/gametypes/_gameobjects::disableobject(); + level.zone.gameobject maps/mp/gametypes/_gameobjects::allowuse( "none" ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::setownerteam( "neutral" ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::setmodelvisibility( 0 ); + level.zone.gameobject maps/mp/gametypes/_gameobjects::mustmaintainclaim( 0 ); + level.zone togglezoneeffects( 0 ); + level notify( "zone_reset" ); + _a539 = level.teams; + _k539 = getFirstArrayKey( _a539 ); + while ( isDefined( _k539 ) ) + { + team = _a539[ _k539 ]; + timerdisplay[ team ].alpha = 0; + _k539 = getNextArrayKey( _a539, _k539 ); + } + spawn_next_zone(); + wait 0,5; + thread forcespawnteam( ownerteam ); + wait 0,5; + } +} + +hidetimerdisplayongameend( timerdisplay ) +{ + level waittill( "game_ended" ); + timerdisplay.alpha = 0; +} + +forcespawnteam( team ) +{ + players = level.players; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( !isDefined( player ) ) + { + i++; + continue; + } + else + { + if ( player.pers[ "team" ] == team ) + { + player notify( "force_spawn" ); + wait 0,1; + } + } + i++; + } +} + +onbeginuse( player ) +{ + ownerteam = self maps/mp/gametypes/_gameobjects::getownerteam(); + if ( ownerteam == "neutral" ) + { + player thread maps/mp/gametypes/_battlechatter_mp::gametypespecificbattlechatter( "hq_protect", player.pers[ "team" ] ); + } + else + { + player thread maps/mp/gametypes/_battlechatter_mp::gametypespecificbattlechatter( "hq_attack", player.pers[ "team" ] ); + } +} + +onenduse( team, player, success ) +{ + player notify( "event_ended" ); +} + +onzonecapture( player ) +{ + capture_team = player.pers[ "team" ]; + capturetime = getTime(); + player logstring( "zone captured" ); + string = &"MP_KOTH_CAPTURED_BY"; + level.zone.gameobject.iscontested = 0; + level.usestartspawns = 0; + if ( !isDefined( self.lastcaptureteam ) || self.lastcaptureteam != capture_team ) + { + touchlist = []; + touchkeys = getarraykeys( self.touchlist[ capture_team ] ); + i = 0; + while ( i < touchkeys.size ) + { + touchlist[ touchkeys[ i ] ] = self.touchlist[ capture_team ][ touchkeys[ i ] ]; + i++; + } + thread give_capture_credit( touchlist, string, capturetime, capture_team, self.lastcaptureteam ); + } + level.kothcapteam = capture_team; + oldteam = maps/mp/gametypes/_gameobjects::getownerteam(); + self maps/mp/gametypes/_gameobjects::setownerteam( capture_team ); + if ( !level.kothmode ) + { + self maps/mp/gametypes/_gameobjects::setusetime( level.destroytime ); + } + _a639 = level.teams; + _k639 = getFirstArrayKey( _a639 ); + while ( isDefined( _k639 ) ) + { + team = _a639[ _k639 ]; + if ( team == capture_team ) + { + while ( isDefined( self.lastcaptureteam ) && self.lastcaptureteam != team ) + { + maps/mp/gametypes/_globallogic_audio::leaderdialog( "koth_secured", team, "gamemode_objective" ); + index = 0; + while ( index < level.players.size ) + { + player = level.players[ index ]; + if ( player.pers[ "team" ] == team ) + { + if ( ( player.lastkilltime + 500 ) > getTime() ) + { + player maps/mp/_challenges::killedlastcontester(); + } + } + index++; + } + } + thread playsoundonplayers( game[ "objective_gained_sound" ], team ); + } + else + { + if ( oldteam == team ) + { + maps/mp/gametypes/_globallogic_audio::leaderdialog( "koth_lost", team, "gamemode_objective" ); + } + else + { + if ( oldteam == "neutral" ) + { + maps/mp/gametypes/_globallogic_audio::leaderdialog( "koth_captured", team, "gamemode_objective" ); + } + } + thread playsoundonplayers( game[ "objective_lost_sound" ], team ); + } + _k639 = getNextArrayKey( _a639, _k639 ); + } + level thread awardcapturepoints( capture_team, self.lastcaptureteam ); + self.capturecount++; + self.lastcaptureteam = capture_team; + self maps/mp/gametypes/_gameobjects::mustmaintainclaim( 1 ); + level notify( "zone_captured" ); + level notify( "zone_captured" + capture_team ); + player notify( "event_ended" ); +} + +give_capture_credit( touchlist, string, capturetime, capture_team, lastcaptureteam ) +{ + wait 0,05; + maps/mp/gametypes/_globallogic_utils::waittillslowprocessallowed(); + players = getarraykeys( touchlist ); + i = 0; + while ( i < players.size ) + { + player = touchlist[ players[ i ] ].player; + player updatecapsperminute( lastcaptureteam ); + if ( !isscoreboosting( player ) ) + { + player maps/mp/_challenges::capturedobjective( capturetime ); + if ( ( level.kothstarttime + 3000 ) > capturetime && level.kothcapteam == capture_team ) + { + maps/mp/_scoreevents::processscoreevent( "quickly_secure_point", player ); + } + maps/mp/_scoreevents::processscoreevent( "koth_secure", player ); + player recordgameevent( "capture" ); + level thread maps/mp/_popups::displayteammessagetoall( string, player ); + if ( isDefined( player.pers[ "captures" ] ) ) + { + player.pers[ "captures" ]++; + player.captures = player.pers[ "captures" ]; + } + if ( ( level.kothstarttime + 500 ) > capturetime ) + { + player maps/mp/_challenges::immediatecapture(); + } + maps/mp/_demo::bookmark( "event", getTime(), player ); + player addplayerstatwithgametype( "CAPTURES", 1 ); + i++; + continue; + } + else + { +/# + player iprintlnbold( "GAMETYPE DEBUG: NOT GIVING YOU CAPTURE CREDIT AS BOOSTING PREVENTION" ); +#/ + } + i++; + } +} + +give_held_credit( touchlist, team ) +{ + wait 0,05; + maps/mp/gametypes/_globallogic_utils::waittillslowprocessallowed(); + players = getarraykeys( touchlist ); + i = 0; + while ( i < players.size ) + { + player = touchlist[ players[ i ] ].player; + i++; + } +} + +onzonedestroy( player ) +{ + destroyed_team = player.pers[ "team" ]; + player logstring( "zone destroyed" ); + maps/mp/_scoreevents::processscoreevent( "zone_destroyed", player ); + player recordgameevent( "destroy" ); + player addplayerstatwithgametype( "DESTRUCTIONS", 1 ); + if ( isDefined( player.pers[ "destructions" ] ) ) + { + player.pers[ "destructions" ]++; + player.destructions = player.pers[ "destructions" ]; + } + destroyteammessage = &"MP_HQ_DESTROYED_BY"; + otherteammessage = &"MP_HQ_DESTROYED_BY_ENEMY"; + if ( level.kothmode ) + { + destroyteammessage = &"MP_KOTH_CAPTURED_BY"; + otherteammessage = &"MP_KOTH_CAPTURED_BY_ENEMY"; + } + level thread maps/mp/_popups::displayteammessagetoall( destroyteammessage, player ); + _a778 = level.teams; + _k778 = getFirstArrayKey( _a778 ); + while ( isDefined( _k778 ) ) + { + team = _a778[ _k778 ]; + if ( team == destroyed_team ) + { + maps/mp/gametypes/_globallogic_audio::leaderdialog( "koth_secured", team, "gamemode_objective" ); + } + else + { + maps/mp/gametypes/_globallogic_audio::leaderdialog( "koth_destroyed", team, "gamemode_objective" ); + } + _k778 = getNextArrayKey( _a778, _k778 ); + } + level notify( "zone_destroyed" ); + if ( level.kothmode ) + { + level thread awardcapturepoints( destroyed_team ); + } + player notify( "event_ended" ); +} + +onzoneunoccupied() +{ + level notify( "zone_destroyed" ); + level.kothcapteam = "neutral"; + level.zone.gameobject.wasleftunoccupied = 1; + level.zone.gameobject.iscontested = 0; +} + +onzonecontested() +{ + zoneowningteam = level.zone.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + level.zone.gameobject.wascontested = 1; + level.zone.gameobject.iscontested = 1; + _a812 = level.teams; + _k812 = getFirstArrayKey( _a812 ); + while ( isDefined( _k812 ) ) + { + team = _a812[ _k812 ]; + if ( team == zoneowningteam ) + { + thread playsoundonplayers( game[ "objective_contested_sound" ], team ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "koth_contested", team, "gamemode_objective" ); + } + _k812 = getNextArrayKey( _a812, _k812 ); + } +} + +onzoneuncontested( lastclaimteam ) +{ +/# + assert( lastclaimteam == level.zone.gameobject maps/mp/gametypes/_gameobjects::getownerteam() ); +#/ + level.zone.gameobject.iscontested = 0; + level.zone.gameobject maps/mp/gametypes/_gameobjects::setclaimteam( lastclaimteam ); +} + +movezoneaftertime( time ) +{ + level endon( "game_ended" ); + level endon( "zone_reset" ); + level.zonemovetime = getTime() + ( time * 1000 ); + level.zonedestroyedbytimer = 0; + wait time; + if ( !isDefined( level.zone.gameobject.wascontested ) || level.zone.gameobject.wascontested == 0 ) + { + if ( !isDefined( level.zone.gameobject.wasleftunoccupied ) || level.zone.gameobject.wasleftunoccupied == 0 ) + { + zoneowningteam = level.zone.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + maps/mp/_challenges::controlzoneentirely( zoneowningteam ); + } + } + level.zonedestroyedbytimer = 1; + level notify( "zone_moved" ); +} + +awardcapturepoints( team, lastcaptureteam ) +{ + level endon( "game_ended" ); + level endon( "zone_destroyed" ); + level endon( "zone_reset" ); + level endon( "zone_moved" ); + level notify( "awardCapturePointsRunning" ); + level endon( "awardCapturePointsRunning" ); + seconds = 1; + score = 1; + while ( !level.gameended ) + { + wait seconds; + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + if ( !level.zone.gameobject.iscontested ) + { + if ( level.scoreperplayer ) + { + score = level.zone.gameobject.numtouching[ team ]; + } + maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( team, score ); + } + } +} + +onspawnplayerunified() +{ + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + spawnpoint = undefined; + if ( !level.usestartspawns ) + { + if ( isDefined( level.zone ) ) + { + if ( isDefined( level.zone.gameobject ) ) + { + zoneowningteam = level.zone.gameobject maps/mp/gametypes/_gameobjects::getownerteam(); + if ( self.pers[ "team" ] == zoneowningteam ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_all, level.zone.gameobject.nearspawns ); + } + else if ( level.spawndelay >= level.zoneautomovetime && getTime() > ( level.zonerevealtime + 10000 ) ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_all ); + } + else + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_all, level.zone.gameobject.outerspawns ); + } + } + } + } + if ( !isDefined( spawnpoint ) ) + { + spawnteam = self.pers[ "team" ]; + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_random( level.spawn_start[ spawnteam ] ); + } +/# + assert( isDefined( spawnpoint ) ); +#/ + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "koth" ); + } +} + +koth_playerspawnedcb() +{ + self.lowermessageoverride = undefined; +} + +comparezoneindexes( zone_a, zone_b ) +{ + script_index_a = zone_a.script_index; + script_index_b = zone_b.script_index; + if ( !isDefined( script_index_a ) && !isDefined( script_index_b ) ) + { + return 0; + } + if ( !isDefined( script_index_a ) && isDefined( script_index_b ) ) + { +/# + println( "KOTH: Missing script_index on zone at " + zone_a.origin ); +#/ + return 1; + } + if ( isDefined( script_index_a ) && !isDefined( script_index_b ) ) + { +/# + println( "KOTH: Missing script_index on zone at " + zone_b.origin ); +#/ + return 0; + } + if ( script_index_a > script_index_b ) + { + return 1; + } + return 0; +} + +getzonearray() +{ + zones = getentarray( "koth_zone_center", "targetname" ); + if ( !isDefined( zones ) ) + { + return undefined; + } + swapped = 1; + n = zones.size; + while ( swapped ) + { + swapped = 0; + i = 0; + while ( i < ( n - 1 ) ) + { + if ( comparezoneindexes( zones[ i ], zones[ i + 1 ] ) ) + { + temp = zones[ i ]; + zones[ i ] = zones[ i + 1 ]; + zones[ i + 1 ] = temp; + swapped = 1; + } + i++; + } + n--; + + } + return zones; +} + +setupzones() +{ + maperrors = []; + zones = getzonearray(); + trigs = getentarray( "koth_zone_trigger", "targetname" ); + i = 0; + while ( i < zones.size ) + { + errored = 0; + zone = zones[ i ]; + zone.trig = undefined; + j = 0; + while ( j < trigs.size ) + { + if ( zone istouching( trigs[ j ] ) ) + { + if ( isDefined( zone.trig ) ) + { + maperrors[ maperrors.size ] = "Zone at " + zone.origin + " is touching more than one "zonetrigger" trigger"; + errored = 1; + break; + } + else zone.trig = trigs[ j ]; + break; + } + else + { + j++; + } + } + if ( !isDefined( zone.trig ) ) + { + if ( !errored ) + { + maperrors[ maperrors.size ] = "Zone at " + zone.origin + " is not inside any "zonetrigger" trigger"; + i++; + continue; + } + } + else + { +/# + assert( !errored ); +#/ + zone.trigorigin = zone.trig.origin; + visuals = []; + visuals[ 0 ] = zone; + while ( isDefined( zone.target ) ) + { + othervisuals = getentarray( zone.target, "targetname" ); + j = 0; + while ( j < othervisuals.size ) + { + visuals[ visuals.size ] = othervisuals[ j ]; + j++; + } + } + objective_name = istring( "objective" ); + precachestring( objective_name ); + zone.gameobject = maps/mp/gametypes/_gameobjects::createuseobject( "neutral", zone.trig, visuals, ( 0, 0, 0 ), objective_name ); + zone.gameobject maps/mp/gametypes/_gameobjects::disableobject(); + zone.gameobject maps/mp/gametypes/_gameobjects::setmodelvisibility( 0 ); + zone.trig.useobj = zone.gameobject; + zone setupnearbyspawns(); + zone createzonespawninfluencer(); + } + i++; + } + if ( maperrors.size > 0 ) + { +/# + println( "^1------------ Map Errors ------------" ); + i = 0; + while ( i < maperrors.size ) + { + println( maperrors[ i ] ); + i++; + } + println( "^1------------------------------------" ); + maps/mp/_utility::error( "Map errors. See above" ); +#/ + maps/mp/gametypes/_callbacksetup::abortlevel(); + return; + } + level.zones = zones; + level.prevzone = undefined; + level.prevzone2 = undefined; + setupzoneexclusions(); + return 1; +} + +setupzoneexclusions() +{ + if ( !isDefined( level.levelkothdisable ) ) + { + return; + } + _a1123 = level.levelkothdisable; + _k1123 = getFirstArrayKey( _a1123 ); + while ( isDefined( _k1123 ) ) + { + nullzone = _a1123[ _k1123 ]; + mindist = 1410065408; + foundzone = undefined; + _a1128 = level.zones; + _k1128 = getFirstArrayKey( _a1128 ); + while ( isDefined( _k1128 ) ) + { + zone = _a1128[ _k1128 ]; + distance = distancesquared( nullzone.origin, zone.origin ); + if ( distance < mindist ) + { + foundzone = zone; + mindist = distance; + } + _k1128 = getNextArrayKey( _a1128, _k1128 ); + } + if ( isDefined( foundzone ) ) + { + if ( !isDefined( foundzone.gameobject.exclusions ) ) + { + foundzone.gameobject.exclusions = []; + } + foundzone.gameobject.exclusions[ foundzone.gameobject.exclusions.size ] = nullzone; + } + _k1123 = getNextArrayKey( _a1123, _k1123 ); + } +} + +setupnearbyspawns() +{ + spawns = level.spawn_all; + i = 0; + while ( i < spawns.size ) + { + spawns[ i ].distsq = distancesquared( spawns[ i ].origin, self.origin ); + i++; + } + i = 1; + while ( i < spawns.size ) + { + thespawn = spawns[ i ]; + j = i - 1; + while ( j >= 0 && thespawn.distsq < spawns[ j ].distsq ) + { + spawns[ j + 1 ] = spawns[ j ]; + j--; + + } + spawns[ j + 1 ] = thespawn; + i++; + } + first = []; + second = []; + third = []; + outer = []; + thirdsize = spawns.size / 3; + i = 0; + while ( i <= thirdsize ) + { + first[ first.size ] = spawns[ i ]; + i++; + } + while ( i < spawns.size ) + { + outer[ outer.size ] = spawns[ i ]; + if ( i <= ( thirdsize * 2 ) ) + { + second[ second.size ] = spawns[ i ]; + i++; + continue; + } + else + { + third[ third.size ] = spawns[ i ]; + } + i++; + } + self.gameobject.nearspawns = first; + self.gameobject.midspawns = second; + self.gameobject.farspawns = third; + self.gameobject.outerspawns = outer; +} + +getfirstzone() +{ + zone = level.zones[ 0 ]; + level.prevzone2 = level.prevzone; + level.prevzone = zone; + level.prevzoneindex = 0; + shufflezones(); + arrayremovevalue( level.zonespawnqueue, zone ); + return zone; +} + +getnextzone() +{ + nextzoneindex = ( level.prevzoneindex + 1 ) % level.zones.size; + zone = level.zones[ nextzoneindex ]; + level.prevzone2 = level.prevzone; + level.prevzone = zone; + level.prevzoneindex = nextzoneindex; + return zone; +} + +pickrandomzonetospawn() +{ + level.prevzoneindex = randomint( level.zones.size ); + zone = level.zones[ level.prevzoneindex ]; + level.prevzone2 = level.prevzone; + level.prevzone = zone; + return zone; +} + +shufflezones() +{ + level.zonespawnqueue = []; + spawnqueue = arraycopy( level.zones ); + total_left = spawnqueue.size; + while ( total_left > 0 ) + { + index = randomint( total_left ); + valid_zones = 0; + zone = 0; + while ( zone < level.zones.size ) + { + if ( !isDefined( spawnqueue[ zone ] ) ) + { + zone++; + continue; + } + else if ( valid_zones == index ) + { + if ( level.zonespawnqueue.size == 0 && isDefined( level.zone ) && level.zone == spawnqueue[ zone ] ) + { + zone++; + continue; + } + else + { + level.zonespawnqueue[ level.zonespawnqueue.size ] = spawnqueue[ zone ]; + total_left--; + continue; + } + else + { + valid_zones++; + } + zone++; + } + } + total_left--; + + } +} + +getnextzonefromqueue() +{ + if ( level.zonespawnqueue.size == 0 ) + { + shufflezones(); + } +/# + assert( level.zonespawnqueue.size > 0 ); +#/ + next_zone = level.zonespawnqueue[ 0 ]; + arrayremoveindex( level.zonespawnqueue, 0 ); + return next_zone; +} + +getcountofteamswithplayers( num ) +{ + has_players = 0; + _a1284 = level.teams; + _k1284 = getFirstArrayKey( _a1284 ); + while ( isDefined( _k1284 ) ) + { + team = _a1284[ _k1284 ]; + if ( num[ team ] > 0 ) + { + has_players++; + } + _k1284 = getNextArrayKey( _a1284, _k1284 ); + } + return has_players; +} + +getpointcost( avgpos, origin ) +{ + avg_distance = 0; + total_error = 0; + distances = []; + _a1299 = avgpos; + team = getFirstArrayKey( _a1299 ); + while ( isDefined( team ) ) + { + position = _a1299[ team ]; + distances[ team ] = distance( origin, avgpos[ team ] ); + avg_distance += distances[ team ]; + team = getNextArrayKey( _a1299, team ); + } + avg_distance /= distances.size; + _a1307 = distances; + team = getFirstArrayKey( _a1307 ); + while ( isDefined( team ) ) + { + dist = _a1307[ team ]; + err = distances[ team ] - avg_distance; + total_error += err * err; + team = getNextArrayKey( _a1307, team ); + } + return total_error; +} + +pickzonetospawn() +{ + _a1322 = level.teams; + _k1322 = getFirstArrayKey( _a1322 ); + while ( isDefined( _k1322 ) ) + { + team = _a1322[ _k1322 ]; + avgpos[ team ] = ( 0, 0, 0 ); + num[ team ] = 0; + _k1322 = getNextArrayKey( _a1322, _k1322 ); + } + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( isalive( player ) ) + { + avgpos[ player.pers[ "team" ] ] += player.origin; + num[ player.pers[ "team" ] ]++; + } + i++; + } + if ( getcountofteamswithplayers( num ) <= 1 ) + { + zone = level.zones[ randomint( level.zones.size ) ]; + while ( isDefined( level.prevzone ) && zone == level.prevzone ) + { + zone = level.zones[ randomint( level.zones.size ) ]; + } + level.prevzone2 = level.prevzone; + level.prevzone = zone; + return zone; + } + _a1350 = level.teams; + _k1350 = getFirstArrayKey( _a1350 ); + while ( isDefined( _k1350 ) ) + { + team = _a1350[ _k1350 ]; + if ( num[ team ] == 0 ) + { + } + else + { + avgpos[ team ] /= num[ team ]; + } + _k1350 = getNextArrayKey( _a1350, _k1350 ); + } + bestzone = undefined; + lowestcost = undefined; + i = 0; + while ( i < level.zones.size ) + { + zone = level.zones[ i ]; + cost = getpointcost( avgpos, zone.origin ); + if ( isDefined( level.prevzone ) && zone == level.prevzone ) + { + i++; + continue; + } + else + { + if ( isDefined( level.prevzone2 ) && zone == level.prevzone2 ) + { + if ( level.zones.size > 2 ) + { + i++; + continue; + } + else cost += 262144; + } + if ( !isDefined( lowestcost ) || cost < lowestcost ) + { + lowestcost = cost; + bestzone = zone; + } + } + i++; + } +/# + assert( isDefined( bestzone ) ); +#/ + level.prevzone2 = level.prevzone; + level.prevzone = bestzone; + return bestzone; +} + +onroundswitch() +{ + game[ "switchedsides" ] = !game[ "switchedsides" ]; +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( isplayer( attacker ) && level.capturetime && !self.touchtriggers.size || !attacker.touchtriggers.size && attacker.pers[ "team" ] == self.pers[ "team" ] ) + { + return; + } + medalgiven = 0; + scoreeventprocessed = 0; + ownerteam = undefined; + if ( level.capturetime == 0 ) + { + if ( !isDefined( level.zone ) ) + { + return; + } + ownerteam = level.zone.gameobject.ownerteam; + if ( !isDefined( ownerteam ) || ownerteam == "neutral" ) + { + return; + } + } + if ( self.touchtriggers.size || level.capturetime == 0 && self istouching( level.zone.trig ) ) + { + if ( level.capturetime > 0 ) + { + triggerids = getarraykeys( self.touchtriggers ); + ownerteam = self.touchtriggers[ triggerids[ 0 ] ].useobj.ownerteam; + } + if ( ownerteam != "neutral" ) + { + attacker.lastkilltime = getTime(); + team = self.pers[ "team" ]; + if ( team == ownerteam ) + { + if ( !medalgiven ) + { + attacker maps/mp/_medals::offenseglobalcount(); + attacker addplayerstatwithgametype( "OFFENDS", 1 ); + medalgiven = 1; + } + maps/mp/_scoreevents::processscoreevent( "hardpoint_kill", attacker, undefined, sweapon ); + self recordkillmodifier( "defending" ); + scoreeventprocessed = 1; + } + else + { + if ( !medalgiven ) + { + if ( isDefined( attacker.pers[ "defends" ] ) ) + { + attacker.pers[ "defends" ]++; + attacker.defends = attacker.pers[ "defends" ]; + } + attacker maps/mp/_medals::defenseglobalcount(); + medalgiven = 1; + attacker addplayerstatwithgametype( "DEFENDS", 1 ); + attacker recordgameevent( "return" ); + } + attacker maps/mp/_challenges::killedzoneattacker( sweapon ); + maps/mp/_scoreevents::processscoreevent( "hardpoint_kill", attacker, undefined, sweapon ); + self recordkillmodifier( "assaulting" ); + scoreeventprocessed = 1; + } + } + } + if ( attacker.touchtriggers.size || level.capturetime == 0 && attacker istouching( level.zone.trig ) ) + { + if ( level.capturetime > 0 ) + { + triggerids = getarraykeys( attacker.touchtriggers ); + ownerteam = attacker.touchtriggers[ triggerids[ 0 ] ].useobj.ownerteam; + } + if ( ownerteam != "neutral" ) + { + team = attacker.pers[ "team" ]; + if ( team == ownerteam ) + { + if ( !medalgiven ) + { + if ( isDefined( attacker.pers[ "defends" ] ) ) + { + attacker.pers[ "defends" ]++; + attacker.defends = attacker.pers[ "defends" ]; + } + attacker maps/mp/_medals::defenseglobalcount(); + medalgiven = 1; + attacker addplayerstatwithgametype( "DEFENDS", 1 ); + attacker recordgameevent( "return" ); + } + if ( scoreeventprocessed == 0 ) + { + attacker maps/mp/_challenges::killedzoneattacker( sweapon ); + maps/mp/_scoreevents::processscoreevent( "hardpoint_kill", attacker, undefined, sweapon ); + self recordkillmodifier( "assaulting" ); + } + } + else + { + if ( !medalgiven ) + { + attacker maps/mp/_medals::offenseglobalcount(); + medalgiven = 1; + attacker addplayerstatwithgametype( "OFFENDS", 1 ); + } + if ( scoreeventprocessed == 0 ) + { + maps/mp/_scoreevents::processscoreevent( "hardpoint_kill", attacker, undefined, sweapon ); + self recordkillmodifier( "defending" ); + } + } + } + } + if ( medalgiven == 1 ) + { + if ( level.zone.gameobject.iscontested == 1 ) + { + attacker thread killwhilecontesting(); + } + } +} + +killwhilecontesting() +{ + self notify( "killWhileContesting" ); + self endon( "killWhileContesting" ); + self endon( "disconnect" ); + killtime = getTime(); + playerteam = self.pers[ "team" ]; + if ( !isDefined( self.clearenemycount ) ) + { + self.clearenemycount = 0; + } + self.clearenemycount++; + zonereturn = level waittill_any_return( "zone_captured" + playerteam, "zone_destroyed", "zone_captured", "death" ); + if ( zonereturn != "zone_destroyed" || zonereturn == "death" && playerteam != self.pers[ "team" ] ) + { + self.clearenemycount = 0; + return; + } + if ( self.clearenemycount >= 2 && ( killtime + 200 ) > getTime() ) + { + maps/mp/_scoreevents::processscoreevent( "clear_2_attackers", self ); + } + self.clearenemycount = 0; +} + +onendgame( winningteam ) +{ + i = 0; + while ( i < level.zones.size ) + { + level.zones[ i ].gameobject maps/mp/gametypes/_gameobjects::allowuse( "none" ); + i++; + } +} + +createzonespawninfluencer() +{ + koth_objective_influencer_score = level.spawnsystem.koth_objective_influencer_score; + koth_objective_influencer_score_curve = level.spawnsystem.koth_objective_influencer_score_curve; + koth_objective_influencer_radius = level.spawnsystem.koth_objective_influencer_radius; + koth_objective_influencer_inner_score = level.spawnsystem.koth_objective_influencer_inner_score; + koth_objective_influencer_inner_score_curve = level.spawnsystem.koth_objective_influencer_inner_score_curve; + koth_objective_influencer_inner_radius = level.spawnsystem.koth_objective_influencer_inner_radius; + self.spawn_influencer = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.gameobject.curorigin, koth_objective_influencer_radius, koth_objective_influencer_score, 0, "koth_objective,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( koth_objective_influencer_score_curve ) ); + self.spawn_influencer_inner = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.gameobject.curorigin, koth_objective_influencer_inner_radius, koth_objective_influencer_inner_score, 0, "koth_objective,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( koth_objective_influencer_inner_score_curve ) ); + self enable_zone_spawn_influencer( 0 ); +} + +enable_zone_spawn_influencer( enabled ) +{ + if ( isDefined( self.spawn_influencer ) ) + { + enableinfluencer( self.spawn_influencer, enabled ); + enableinfluencer( self.spawn_influencer_inner, enabled ); + } +} + +koth_gamemodespawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.koth_objective_influencer_score = set_dvar_float_if_unset( "scr_spawn_koth_objective_influencer_score", "200", reset_dvars ); + ss.koth_objective_influencer_score_curve = set_dvar_if_unset( "scr_spawn_koth_objective_influencer_score_curve", "linear", reset_dvars ); + ss.koth_objective_influencer_radius = set_dvar_float_if_unset( "scr_spawn_koth_objective_influencer_radius", "" + 4000, reset_dvars ); + ss.koth_objective_influencer_inner_score = -800; + ss.koth_objective_influencer_inner_score_curve = "constant"; + ss.koth_objective_influencer_inner_radius = 1000; + ss.koth_initial_spawns_influencer_score = set_dvar_float_if_unset( "scr_spawn_koth_initial_spawns_influencer_score", "200", reset_dvars ); + ss.koth_initial_spawns_influencer_score_curve = set_dvar_if_unset( "scr_spawn_koth_initial_spawns_influencer_score_curve", "linear", reset_dvars ); + ss.koth_initial_spawns_influencer_radius = set_dvar_float_if_unset( "scr_spawn_koth_initial_spawns_influencer_radius", "" + ( 10 * get_player_height() ), reset_dvars ); +} + +updatecapsperminute( lastownerteam ) +{ + if ( !isDefined( self.capsperminute ) ) + { + self.numcaps = 0; + self.capsperminute = 0; + } + if ( !isDefined( lastownerteam ) || lastownerteam == "neutral" ) + { + return; + } + self.numcaps++; + minutespassed = maps/mp/gametypes/_globallogic_utils::gettimepassed() / 60000; + if ( isplayer( self ) && isDefined( self.timeplayed[ "total" ] ) ) + { + minutespassed = self.timeplayed[ "total" ] / 60; + } + self.capsperminute = self.numcaps / minutespassed; + if ( self.capsperminute > self.numcaps ) + { + self.capsperminute = self.numcaps; + } +} + +isscoreboosting( player ) +{ + if ( !level.rankedmatch ) + { + return 0; + } + if ( player.capsperminute > level.playercapturelpm ) + { + return 1; + } + return 0; +} diff --git a/patch_mp/maps/mp/gametypes/oic.gsc b/patch_mp/maps/mp/gametypes/oic.gsc new file mode 100644 index 0000000..b018b22 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/oic.gsc @@ -0,0 +1,361 @@ +#include maps/mp/gametypes/_persistence; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_wager; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + level.pointsperweaponkill = getgametypesetting( "pointsPerWeaponKill" ); + level.pointspermeleekill = getgametypesetting( "pointsPerMeleeKill" ); + level.pointsforsurvivalbonus = getgametypesetting( "pointsForSurvivalBonus" ); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 50000 ); + registerroundlimit( 0, 10 ); + registerroundwinlimit( 0, 10 ); + registernumlives( 1, 100 ); + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.givecustomloadout = ::givecustomloadout; + level.onplayerkilled = ::onplayerkilled; + level.onplayerdamage = ::onplayerdamage; + level.onwagerawards = ::onwagerawards; + game[ "dialog" ][ "gametype" ] = "oic_start"; + game[ "dialog" ][ "wm_2_lives" ] = "oic_2life"; + game[ "dialog" ][ "wm_final_life" ] = "oic_last"; + precachestring( &"MPUI_PLAYER_KILLED" ); + precachestring( &"MP_PLUS_ONE_BULLET" ); + precachestring( &"MP_OIC_SURVIVOR_BONUS" ); + precacheitem( "kard_wager_mp" ); + setscoreboardcolumns( "pointstowin", "kills", "deaths", "stabs", "survived" ); +} + +onplayerdamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime ) +{ + if ( smeansofdeath != "MOD_PISTOL_BULLET" || smeansofdeath == "MOD_RIFLE_BULLET" && smeansofdeath == "MOD_HEAD_SHOT" ) + { + idamage = self.maxhealth + 1; + } + return idamage; +} + +givecustomloadout() +{ + weapon = "kard_wager_mp"; + self maps/mp/gametypes/_wager::setupblankrandomplayer( 1, 1, weapon ); + self giveweapon( weapon ); + self giveweapon( "knife_mp" ); + self switchtoweapon( weapon ); + clipammo = 1; + if ( isDefined( self.pers[ "clip_ammo" ] ) ) + { + clipammo = self.pers[ "clip_ammo" ]; + } + self setweaponammoclip( weapon, clipammo ); + stockammo = 0; + if ( isDefined( self.pers[ "stock_ammo" ] ) ) + { + stockammo = self.pers[ "stock_ammo" ]; + } + self setweaponammostock( weapon, stockammo ); + self setspawnweapon( weapon ); + self setperk( "specialty_unlimitedsprint" ); + self setperk( "specialty_movefaster" ); + return weapon; +} + +onstartgametype() +{ + setclientnamemode( "auto_change" ); + setobjectivetext( "allies", &"OBJECTIVES_DM" ); + setobjectivetext( "axis", &"OBJECTIVES_DM" ); + if ( level.splitscreen ) + { + setobjectivescoretext( "allies", &"OBJECTIVES_DM" ); + setobjectivescoretext( "axis", &"OBJECTIVES_DM" ); + } + else + { + setobjectivescoretext( "allies", &"OBJECTIVES_DM_SCORE" ); + setobjectivescoretext( "axis", &"OBJECTIVES_DM_SCORE" ); + } + allowed[ 0 ] = "oic"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 0 ); + level.spawnmaxs = ( 0, 0, 0 ); + newspawns = getentarray( "mp_wager_spawn", "classname" ); + if ( newspawns.size > 0 ) + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_wager_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_wager_spawn" ); + } + else + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_dm_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_dm_spawn" ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.usestartspawns = 0; + level.displayroundendtext = 0; + if ( level.roundlimit != 1 && level.numlives ) + { + level.overrideplayerscore = 1; + level.displayroundendtext = 1; + level.onendgame = ::onendgame; + } + level thread watchelimination(); + setobjectivehinttext( "allies", &"OBJECTIVES_OIC_HINT" ); + setobjectivehinttext( "axis", &"OBJECTIVES_OIC_HINT" ); +} + +onspawnplayerunified() +{ + maps/mp/gametypes/_spawning::onspawnplayer_unified(); + livesleft = self.pers[ "lives" ]; + if ( livesleft == 2 ) + { + self maps/mp/gametypes/_wager::wagerannouncer( "wm_2_lives" ); + } + else + { + if ( livesleft == 1 ) + { + self maps/mp/gametypes/_wager::wagerannouncer( "wm_final_life" ); + } + } +} + +onspawnplayer( predictedspawn ) +{ + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( self.pers[ "team" ] ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_dm( spawnpoints ); + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "oic" ); + } +} + +onendgame( winningplayer ) +{ + if ( isDefined( winningplayer ) && isplayer( winningplayer ) ) + { + [[ level._setplayerscore ]]( winningplayer, [[ level._getplayerscore ]]( winningplayer ) + 1 ); + } +} + +onstartwagersidebets() +{ + thread saveoffallplayersammo(); +} + +saveoffallplayersammo() +{ + wait 1; + playerindex = 0; + while ( playerindex < level.players.size ) + { + player = level.players[ playerindex ]; + if ( !isDefined( player ) ) + { + playerindex++; + continue; + } + else if ( player.pers[ "lives" ] == 0 ) + { + playerindex++; + continue; + } + else + { + currentweapon = player getcurrentweapon(); + player.pers[ "clip_ammo" ] = player getweaponammoclip( currentweapon ); + player.pers[ "stock_ammo" ] = player getweaponammostock( currentweapon ); + } + playerindex++; + } +} + +isplayereliminated( player ) +{ + if ( isDefined( player.pers[ "eliminated" ] ) ) + { + return player.pers[ "eliminated" ]; + } +} + +getplayersleft() +{ + playersremaining = []; + playerindex = 0; + while ( playerindex < level.players.size ) + { + player = level.players[ playerindex ]; + if ( !isDefined( player ) ) + { + playerindex++; + continue; + } + else + { + if ( !isplayereliminated( player ) ) + { + playersremaining[ playersremaining.size ] = player; + } + } + playerindex++; + } + return playersremaining; +} + +onwagerfinalizeround() +{ + playersleft = getplayersleft(); + lastmanstanding = playersleft[ 0 ]; + sidebetpool = 0; + sidebetwinners = []; + players = level.players; + playerindex = 0; + while ( playerindex < players.size ) + { + if ( isDefined( players[ playerindex ].pers[ "sideBetMade" ] ) ) + { + sidebetpool += getDvarInt( "scr_wagerSideBet" ); + if ( players[ playerindex ].pers[ "sideBetMade" ] == lastmanstanding.name ) + { + sidebetwinners[ sidebetwinners.size ] = players[ playerindex ]; + } + } + playerindex++; + } + if ( sidebetwinners.size == 0 ) + { + return; + } + sidebetpayout = int( sidebetpool / sidebetwinners.size ); + index = 0; + while ( index < sidebetwinners.size ) + { + player = sidebetwinners[ index ]; + player.pers[ "wager_sideBetWinnings" ] += sidebetpayout; + index++; + } +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( isDefined( attacker ) && isplayer( attacker ) && self != attacker ) + { + attackerammo = attacker getammocount( "kard_wager_mp" ); + victimammo = self getammocount( "kard_wager_mp" ); + attacker giveammo( 1 ); + attacker thread maps/mp/gametypes/_wager::queuewagerpopup( &"MPUI_PLAYER_KILLED", 0, &"MP_PLUS_ONE_BULLET" ); + attacker playlocalsound( "mpl_oic_bullet_pickup" ); + if ( smeansofdeath == "MOD_MELEE" ) + { + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.pointspermeleekill ); + if ( attackerammo > 0 ) + { + maps/mp/_scoreevents::processscoreevent( "knife_with_ammo_oic", attacker, self, sweapon ); + } + if ( victimammo > attackerammo ) + { + maps/mp/_scoreevents::processscoreevent( "kill_enemy_with_more_ammo_oic", attacker, self, sweapon ); + } + } + else + { + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.pointsperweaponkill ); + if ( victimammo > ( attackerammo + 1 ) ) + { + maps/mp/_scoreevents::processscoreevent( "kill_enemy_with_more_ammo_oic", attacker, self, sweapon ); + } + } + if ( self.pers[ "lives" ] == 0 ) + { + maps/mp/_scoreevents::processscoreevent( "eliminate_oic", attacker, self, sweapon ); + } + } +} + +giveammo( amount ) +{ + currentweapon = self getcurrentweapon(); + clipammo = self getweaponammoclip( currentweapon ); + self setweaponammoclip( currentweapon, clipammo + amount ); +} + +shouldreceivesurvivorbonus() +{ + if ( isalive( self ) ) + { + return 1; + } + if ( self.hasspawned && self.pers[ "lives" ] > 0 ) + { + return 1; + } + return 0; +} + +watchelimination() +{ + level endon( "game_ended" ); + for ( ;; ) + { + level waittill( "player_eliminated" ); + players = level.players; + i = 0; + while ( i < players.size ) + { + if ( isDefined( players[ i ] ) && players[ i ] shouldreceivesurvivorbonus() ) + { + players[ i ].pers[ "survived" ]++; + players[ i ].survived = players[ i ].pers[ "survived" ]; + players[ i ] thread maps/mp/gametypes/_wager::queuewagerpopup( &"MP_OIC_SURVIVOR_BONUS", 10 ); + score = maps/mp/gametypes/_globallogic_score::_getplayerscore( players[ i ] ); + maps/mp/_scoreevents::processscoreevent( "survivor", players[ i ] ); + players[ i ] maps/mp/gametypes/_globallogic_score::givepointstowin( level.pointsforsurvivalbonus ); + } + i++; + } + } +} + +onwagerawards() +{ + stabs = self maps/mp/gametypes/_globallogic_score::getpersstat( "stabs" ); + if ( !isDefined( stabs ) ) + { + stabs = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", stabs, 0 ); + longshots = self maps/mp/gametypes/_globallogic_score::getpersstat( "longshots" ); + if ( !isDefined( longshots ) ) + { + longshots = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", longshots, 1 ); + bestkillstreak = self maps/mp/gametypes/_globallogic_score::getpersstat( "best_kill_streak" ); + if ( !isDefined( bestkillstreak ) ) + { + bestkillstreak = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", bestkillstreak, 2 ); +} diff --git a/patch_mp/maps/mp/gametypes/oneflag.gsc b/patch_mp/maps/mp/gametypes/oneflag.gsc new file mode 100644 index 0000000..a34ff7c --- /dev/null +++ b/patch_mp/maps/mp/gametypes/oneflag.gsc @@ -0,0 +1,1369 @@ +#include maps/mp/gametypes/_rank; +#include maps/mp/gametypes/_globallogic_defaults; +#include maps/mp/_challenges; +#include maps/mp/_demo; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_weapons; +#include maps/mp/_popups; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/teams/_teams; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +main() +{ + if ( getDvar( "mapname" ) == "mp_background" ) + { + return; + } + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registertimelimit( 0, 1440 ); + registerroundlimit( 0, 10 ); + registerroundwinlimit( 0, 10 ); + registerroundswitch( 0, 9 ); + registernumlives( 0, 100 ); + registerscorelimit( 0, 5000 ); + level.scoreroundbased = getgametypesetting( "roundscorecarry" ) == 0; + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + if ( getDvar( "scr_ctf_spawnPointFacingAngle" ) == "" ) + { + setdvar( "scr_ctf_spawnPointFacingAngle", "0" ); + } + level.teambased = 1; + level.overrideteamscore = 1; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onprecachegametype = ::onprecachegametype; + level.onplayerkilled = ::onplayerkilled; + level.onroundswitch = ::onroundswitch; + level.onendgame = ::onendgame; + level.onroundendgame = ::onroundendgame; + level.gamemodespawndvars = ::ctf_gamemodespawndvars; + level.getteamkillpenalty = ::ctf_getteamkillpenalty; + level.getteamkillscore = ::ctf_getteamkillscore; + level.setmatchscorehudelemforteam = ::setmatchscorehudelemforteam; + level.shouldplayovertimeround = ::shouldplayovertimeround; + if ( !isDefined( game[ "ctf_teamscore" ] ) ) + { + game[ "ctf_teamscore" ][ "allies" ] = 0; + game[ "ctf_teamscore" ][ "axis" ] = 0; + } + game[ "dialog" ][ "gametype" ] = "ctf_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "hcctf_start"; + game[ "dialog" ][ "wetake_flag" ] = "ctf_wetake"; + game[ "dialog" ][ "theytake_flag" ] = "ctf_theytake"; + game[ "dialog" ][ "theydrop_flag" ] = "ctf_theydrop"; + game[ "dialog" ][ "wedrop_flag" ] = "ctf_wedrop"; + game[ "dialog" ][ "wereturn_flag" ] = "ctf_wereturn"; + game[ "dialog" ][ "theyreturn_flag" ] = "ctf_theyreturn"; + game[ "dialog" ][ "theycap_flag" ] = "ctf_theycap"; + game[ "dialog" ][ "wecap_flag" ] = "ctf_wecap"; + game[ "dialog" ][ "offense_obj" ] = "cap_start"; + game[ "dialog" ][ "defense_obj" ] = "cap_start"; + level.lastdialogtime = getTime(); + level thread ctf_icon_hide(); + if ( !sessionmodeissystemlink() && !sessionmodeisonlinegame() && issplitscreen() ) + { + setscoreboardcolumns( "score", "kills", "captures", "defends", "deaths" ); + } + else + { + setscoreboardcolumns( "score", "kills", "deaths", "captures", "defends" ); + } + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "ctf_flag", 0 ); + maps/mp/gametypes/_globallogic_audio::registerdialoggroup( "ctf_flag_enemy", 0 ); +} + +onprecachegametype() +{ + game[ "flag_dropped_sound" ] = "mp_war_objective_lost"; + game[ "flag_recovered_sound" ] = "mp_war_objective_taken"; + game[ "strings" ][ "flag_respawning_in" ] = &"MP_FLAG_RESPAWNING_IN"; + precachemodel( maps/mp/teams/_teams::getteamflagmodel( "allies" ) ); + precachemodel( maps/mp/teams/_teams::getteamflagmodel( "axis" ) ); + precachemodel( maps/mp/teams/_teams::getteamflagmodel( "neutral" ) ); + precachemodel( maps/mp/teams/_teams::getteamflagcarrymodel( "allies" ) ); + precachemodel( maps/mp/teams/_teams::getteamflagcarrymodel( "axis" ) ); + precacheshader( maps/mp/teams/_teams::getteamflagicon( "allies" ) ); + precacheshader( maps/mp/teams/_teams::getteamflagicon( "axis" ) ); + precachestring( &"MP_FLAG_TAKEN_BY" ); + precachestring( &"MP_ENEMY_FLAG_TAKEN" ); + precachestring( &"MP_FRIENDLY_FLAG_TAKEN" ); + precachestring( &"MP_FLAG_CAPTURED_BY" ); + precachestring( &"MP_ENEMY_FLAG_CAPTURED_BY" ); + precachestring( &"MP_FLAG_RETURNED_BY" ); + precachestring( &"MP_FLAG_RETURNED" ); + precachestring( &"MP_ENEMY_FLAG_RETURNED" ); + precachestring( &"MP_FRIENDLY_FLAG_RETURNED" ); + precachestring( &"MP_YOUR_FLAG_RETURNING_IN" ); + precachestring( &"MP_ENEMY_FLAG_RETURNING_IN" ); + precachestring( &"MP_FRIENDLY_FLAG_DROPPED_BY" ); + precachestring( &"MP_FRIENDLY_FLAG_DROPPED" ); + precachestring( &"MP_ENEMY_FLAG_DROPPED" ); + precachestring( &"MP_NEUTRAL_FLAG_DROPPED" ); + precachestring( &"MP_NEUTRAL_FLAG_TAKEN" ); + precachestring( &"MP_NEUTRAL_FLAG_CAPTURED" ); + precachestring( &"MP_SUDDEN_DEATH" ); + precachestring( &"MP_CAP_LIMIT_REACHED" ); + precachestring( &"MP_CTF_CANT_CAPTURE_FLAG" ); + precachestring( &"MP_CTF_OVERTIME_WIN" ); + precachestring( &"MP_ONE_FLAG_CTF_OVERTIME_ROUND_1" ); + precachestring( &"MP_ONE_FLAG_CTF_OVERTIME_ROUND_2_WINNER" ); + precachestring( &"MP_ONE_FLAG_CTF_OVERTIME_ROUND_2_LOSER" ); + precachestring( &"MP_ONE_FLAG_CTF_OVERTIME_ROUND_2_TIE" ); + precachestring( &"MPUI_CTF_OVERTIME_FASTEST_CAP_TIME" ); + precachestring( &"MP_ONE_FLAG_CTF_OVERTIME_DEFEAT_TIMELIMIT" ); + precachestring( &"MP_ONE_FLAG_CTF_OVERTIME_DEFEAT_DID_NOT_DEFEND" ); + precachestring( &"MENU_NEUTRAL" ); + precachestring( &"MENU_FLAG_RESPAWNING" ); + precachestring( &"allies_base" ); + precachestring( &"axis_base" ); + precachestring( &"allies_flag" ); + precachestring( &"axis_flag" ); + precachestring( &"neutral_flag" ); + precachestring( game[ "strings" ][ "flag_respawning_in" ] ); + game[ "strings" ][ "score_limit_reached" ] = &"MP_CAP_LIMIT_REACHED"; +} + +onstartgametype() +{ + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } +/# + setdebugsideswitch( game[ "switchedsides" ] ); +#/ + setclientnamemode( "auto_change" ); + maps/mp/gametypes/_globallogic_score::resetteamscores(); + setobjectivetext( "allies", &"OBJECTIVES_ONEFLAG" ); + setobjectivetext( "axis", &"OBJECTIVES_ONEFLAG" ); + if ( level.splitscreen ) + { + setobjectivescoretext( "allies", &"OBJECTIVES_ONEFLAG" ); + setobjectivescoretext( "axis", &"OBJECTIVES_ONEFLAG" ); + } + else + { + setobjectivescoretext( "allies", &"OBJECTIVES_ONEFLAG_SCORE" ); + setobjectivescoretext( "axis", &"OBJECTIVES_ONEFLAG_SCORE" ); + } + setobjectivehinttext( "allies", &"OBJECTIVES_ONE_FLAG_HINT" ); + setobjectivehinttext( "axis", &"OBJECTIVES_ONE_FLAG_HINT" ); + if ( isDefined( game[ "overtime_round" ] ) ) + { + [[ level._setteamscore ]]( "allies", 0 ); + [[ level._setteamscore ]]( "axis", 0 ); + registerscorelimit( 1, 1 ); + if ( isDefined( game[ "ctf_overtime_time_to_beat" ] ) ) + { + registertimelimit( game[ "ctf_overtime_time_to_beat" ] / 60000, game[ "ctf_overtime_time_to_beat" ] / 60000 ); + } + if ( game[ "overtime_round" ] == 1 ) + { + setobjectivehinttext( "allies", &"MP_CTF_OVERTIME_ROUND_1" ); + setobjectivehinttext( "axis", &"MP_CTF_OVERTIME_ROUND_1" ); + } + else if ( isDefined( game[ "ctf_overtime_first_winner" ] ) ) + { + setobjectivehinttext( game[ "ctf_overtime_first_winner" ], &"MP_ONE_FLAG_CTF_OVERTIME_ROUND_2_WINNER" ); + setobjectivehinttext( getotherteam( game[ "ctf_overtime_first_winner" ] ), &"MP_ONE_FLAG_CTF_OVERTIME_ROUND_2_LOSER" ); + } + else + { + setobjectivehinttext( "allies", &"MP_ONE_FLAG_CTF_OVERTIME_ROUND_2_TIE" ); + setobjectivehinttext( "axis", &"MP_ONE_FLAG_CTF_OVERTIME_ROUND_2_TIE" ); + } + } + allowed[ 0 ] = "ctf"; + allowed[ 1 ] = "dom"; + maps/mp/gametypes/_gameobjects::main( allowed ); + entities = getentarray(); + entity_index = entities.size - 1; + while ( entity_index >= 0 ) + { + entity = entities[ entity_index ]; + while ( isDefined( entity.script_gameobjectname ) && entity.script_gameobjectname != "[all_modes]" ) + { + gameobjectnames = strtok( entity.script_gameobjectname, " " ); + i = 0; + while ( i < gameobjectnames.size ) + { + if ( gameobjectnames[ i ] == "ctf" && gameobjectnames.size > 1 ) + { + entity delete(); + entity_index--; + continue; + } + else + { + i++; + } + } + } + entity_index--; + + } + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, -1 ); + level.spawnmaxs = ( 0, 0, -1 ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_ctf_spawn_allies_start" ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_ctf_spawn_axis_start" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_ctf_spawn_allies" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_ctf_spawn_axis" ); + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.spawn_axis = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_ctf_spawn_axis" ); + level.spawn_allies = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_ctf_spawn_allies" ); + level.spawn_start = []; + _a283 = level.teams; + _k283 = getFirstArrayKey( _a283 ); + while ( isDefined( _k283 ) ) + { + team = _a283[ _k283 ]; + level.spawn_start[ team ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_ctf_spawn_" + team + "_start" ); + _k283 = getNextArrayKey( _a283, _k283 ); + } + level.oneflagtimer = createservertimer( "objective", 1,4 ); + level.oneflagtimer.x = 11; + level.oneflagtimer.y = 120; + level.oneflagtimer.horzalign = "user_left"; + level.oneflagtimer.vertalign = "user_top"; + level.oneflagtimer.alignx = "left"; + level.oneflagtimer.aligny = "top"; + level.oneflagtimer.label = game[ "strings" ][ "flag_respawning_in" ]; + level.oneflagtimer.font = "small"; + level.oneflagtimer.alpha = 0; + level.oneflagtimer.archived = 0; + level.oneflagtimer.hidewheninmenu = 1; + level.oneflagtimer.hidewheninkillcam = 1; + level.oneflagtimer.showplayerteamhudelemtospectator = 1; + thread hidetimerdisplayongameend( level.oneflagtimer ); + thread updategametypedvars(); + thread ctf(); +} + +hidetimerdisplayongameend( timerdisplay ) +{ + level waittill( "game_ended" ); + timerdisplay.alpha = 0; +} + +shouldplayovertimeround() +{ + if ( isDefined( game[ "overtime_round" ] ) ) + { + if ( game[ "overtime_round" ] == 1 || !level.gameended ) + { + return 1; + } + return 0; + } + if ( level.roundscorecarry ) + { + if ( game[ "teamScores" ][ "allies" ] == game[ "teamScores" ][ "axis" ] || hitroundlimit() && game[ "teamScores" ][ "allies" ] == ( level.scorelimit - 1 ) ) + { + return 1; + } + } + else + { + alliesroundswon = getroundswon( "allies" ); + axisroundswon = getroundswon( "axis" ); + if ( level.roundwinlimit > 0 && axisroundswon == ( level.roundwinlimit - 1 ) && alliesroundswon == ( level.roundwinlimit - 1 ) ) + { + return 1; + } + if ( hitroundlimit() && alliesroundswon == axisroundswon ) + { + return 1; + } + } + return 0; +} + +minutesandsecondsstring( milliseconds ) +{ + minutes = floor( milliseconds / 60000 ); + milliseconds -= minutes * 60000; + seconds = floor( milliseconds / 1000 ); + if ( seconds < 10 ) + { + return ( minutes + ":0" ) + seconds; + } + else + { + return ( minutes + ":" ) + seconds; + } +} + +setmatchscorehudelemforteam( team ) +{ + if ( !isDefined( game[ "overtime_round" ] ) ) + { + self maps/mp/gametypes/_hud_message::setmatchscorehudelemforteam( team ); + } + else if ( isDefined( game[ "ctf_overtime_second_winner" ] ) && game[ "ctf_overtime_second_winner" ] == team ) + { + self settext( minutesandsecondsstring( game[ "ctf_overtime_best_time" ] ) ); + } + else + { + if ( isDefined( game[ "ctf_overtime_first_winner" ] ) && game[ "ctf_overtime_first_winner" ] == team ) + { + self settext( minutesandsecondsstring( game[ "ctf_overtime_time_to_beat" ] ) ); + return; + } + else + { + self settext( &"" ); + } + } +} + +onroundswitch() +{ + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + level.halftimetype = "halftime"; + game[ "switchedsides" ] = !game[ "switchedsides" ]; +} + +onendgame( winningteam ) +{ + if ( isDefined( game[ "overtime_round" ] ) ) + { + if ( game[ "overtime_round" ] == 1 ) + { + if ( isDefined( winningteam ) && winningteam != "tie" ) + { + game[ "ctf_overtime_first_winner" ] = winningteam; + game[ "ctf_overtime_time_to_beat" ] = maps/mp/gametypes/_globallogic_utils::gettimepassed(); + } + return; + } + else + { + game[ "ctf_overtime_second_winner" ] = winningteam; + game[ "ctf_overtime_best_time" ] = maps/mp/gametypes/_globallogic_utils::gettimepassed(); + } + } +} + +onroundendgame( winningteam ) +{ + if ( isDefined( game[ "overtime_round" ] ) ) + { + if ( isDefined( game[ "ctf_overtime_first_winner" ] ) ) + { + if ( !isDefined( winningteam ) || winningteam == "tie" ) + { + winningteam = game[ "ctf_overtime_first_winner" ]; + } + if ( game[ "ctf_overtime_first_winner" ] == winningteam ) + { + level.endvictoryreasontext = &"MPUI_CTF_OVERTIME_FASTEST_CAP_TIME"; + level.enddefeatreasontext = &"MP_ONE_FLAG_CTF_OVERTIME_DEFEAT_TIMELIMIT"; + } + else + { + level.endvictoryreasontext = &"MPUI_CTF_OVERTIME_FASTEST_CAP_TIME"; + level.enddefeatreasontext = &"MP_ONE_FLAG_CTF_OVERTIME_DEFEAT_DID_NOT_DEFEND"; + } + } + else + { + if ( !isDefined( winningteam ) || winningteam == "tie" ) + { + return "tie"; + } + } + return winningteam; + } + if ( level.roundscorecarry == 0 ) + { + _a451 = level.teams; + _k451 = getFirstArrayKey( _a451 ); + while ( isDefined( _k451 ) ) + { + team = _a451[ _k451 ]; + [[ level._setteamscore ]]( team, game[ "roundswon" ][ team ] ); + _k451 = getNextArrayKey( _a451, _k451 ); + } + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbygamestat( "roundswon" ); + } + else + { + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbyteamscore(); + } + return winner; +} + +onspawnplayerunified() +{ + self.isflagcarrier = 0; + self.flagcarried = undefined; + self clearclientflag( 0 ); + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + self.isflagcarrier = 0; + self.flagcarried = undefined; + self clearclientflag( 0 ); + spawnteam = self.pers[ "team" ]; + if ( game[ "switchedsides" ] ) + { + spawnteam = getotherteam( spawnteam ); + } + if ( level.usestartspawns ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_random( level.spawn_start[ spawnteam ] ); + } + else if ( spawnteam == "axis" ) + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_axis ); + } + else + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( level.spawn_allies ); + } +/# + assert( isDefined( spawnpoint ) ); +#/ + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "ctf" ); + } +} + +updategametypedvars() +{ + level.flagcapturetime = getgametypesetting( "captureTime" ); + level.flagtouchreturntime = getgametypesetting( "defuseTime" ); + level.idleflagreturntime = getgametypesetting( "idleFlagResetTime" ); + level.flagrespawntime = getgametypesetting( "flagRespawnTime" ); + level.enemycarriervisible = getgametypesetting( "enemyCarrierVisible" ); + level.roundlimit = getgametypesetting( "roundLimit" ); + level.roundscorecarry = getgametypesetting( "roundscorecarry" ); + level.teamkillpenaltymultiplier = getgametypesetting( "teamKillPenalty" ); + level.teamkillscoremultiplier = getgametypesetting( "teamKillScore" ); + if ( level.flagtouchreturntime >= 0 && level.flagtouchreturntime != 63 ) + { + level.touchreturn = 1; + } + else + { + level.touchreturn = 0; + } +} + +createflag( trigger ) +{ + if ( isDefined( trigger.target ) ) + { + visuals[ 0 ] = getent( trigger.target, "targetname" ); + } + else + { + visuals[ 0 ] = spawn( "script_model", trigger.origin ); + visuals[ 0 ].angles = trigger.angles; + } + entityteam = trigger.script_team; + if ( game[ "switchedsides" ] && isDefined( entityteam ) ) + { + entityteam = getotherteam( entityteam ); + } + if ( !isDefined( entityteam ) ) + { + entityteam = "neutral"; + trigger.radius = 25; + trigger.height = 100; + } + visuals[ 0 ] setmodel( maps/mp/teams/_teams::getteamflagmodel( entityteam ) ); + visuals[ 0 ] setteam( entityteam ); + flag = maps/mp/gametypes/_gameobjects::createcarryobject( entityteam, trigger, visuals, vectorScale( ( 0, 0, -1 ), 100 ), istring( entityteam + "_flag" ) ); + flag maps/mp/gametypes/_gameobjects::setteamusetime( "friendly", level.flagtouchreturntime ); + flag maps/mp/gametypes/_gameobjects::setteamusetime( "enemy", level.flagcapturetime ); + flag maps/mp/gametypes/_gameobjects::setteamusetime( "neutral", level.flagcapturetime ); + flag maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + if ( entityteam != "neutral" ) + { + flag maps/mp/gametypes/_gameobjects::setvisiblecarriermodel( maps/mp/teams/_teams::getteamflagcarrymodel( entityteam ) ); + flag maps/mp/gametypes/_gameobjects::setcarryicon( maps/mp/teams/_teams::getteamflagicon( entityteam ) ); + flag.visuals[ 0 ] hide(); + } + else + { + flag maps/mp/gametypes/_gameobjects::setvisiblecarriermodel( maps/mp/teams/_teams::getteamflagcarrymodel( "allies" ) ); + flag maps/mp/gametypes/_gameobjects::setcarryicon( maps/mp/teams/_teams::getteamflagicon( "allies" ) ); + } + flag maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.icondefend2d ); + flag maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.icondefend3d ); + flag maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconcapture2d ); + flag maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconcapture3d ); + if ( level.enemycarriervisible == 2 ) + { + flag.objidpingfriendly = 1; + } + flag.allowweapons = 1; + flag.onpickup = ::onpickup; + flag.onpickupfailed = ::onpickup; + flag.ondrop = ::ondrop; + flag.onreset = ::onreset; + if ( level.idleflagreturntime > 0 ) + { + flag.autoresettime = level.idleflagreturntime; + } + else + { + flag.autoresettime = undefined; + } + if ( entityteam != "neutral" ) + { + flag thread watchforscore(); + } + return flag; +} + +createflagzone( trigger ) +{ + visuals = []; + entityteam = trigger.script_team; + if ( game[ "switchedsides" ] ) + { + entityteam = getotherteam( entityteam ); + } + flagzone = maps/mp/gametypes/_gameobjects::createuseobject( entityteam, trigger, visuals, ( 0, 0, -1 ), istring( entityteam + "_base" ) ); + flagzone maps/mp/gametypes/_gameobjects::allowuse( "friendly" ); + flagzone maps/mp/gametypes/_gameobjects::setusetime( 0 ); + flagzone maps/mp/gametypes/_gameobjects::setusetext( &"MP_CAPTURING_FLAG" ); + flagzone maps/mp/gametypes/_gameobjects::setvisibleteam( "friendly" ); + enemyteam = getotherteam( entityteam ); + flagzone maps/mp/gametypes/_gameobjects::setkeyobject( level.teamflags[ enemyteam ] ); + flagzone.onuse = ::oncapture; + flag = level.teamflags[ entityteam ]; + flag.flagbase = flagzone; + flagzone.flag = flag; + tracestart = trigger.origin + vectorScale( ( 0, 0, -1 ), 32 ); + traceend = trigger.origin + vectorScale( ( 0, 0, -1 ), 32 ); + trace = bullettrace( tracestart, traceend, 0, undefined ); + upangles = vectorToAngle( trace[ "normal" ] ); + flagzone.baseeffectforward = anglesToForward( upangles ); + flagzone.baseeffectright = anglesToRight( upangles ); + flagzone.baseeffectpos = trace[ "position" ]; + flagzone thread resetflagbaseeffect(); + flagzone createflagspawninfluencer( entityteam ); + return flagzone; +} + +createflaghint( team, origin ) +{ + radius = 128; + height = 64; + trigger = spawn( "trigger_radius", origin, 0, radius, height ); + trigger sethintstring( &"MP_CTF_CANT_CAPTURE_FLAG" ); + trigger setcursorhint( "HINT_NOICON" ); + trigger.original_origin = origin; + trigger turn_off(); + return trigger; +} + +ctf() +{ + level.flags = []; + level.teamflags = []; + level.flagzones = []; + level.teamflagzones = []; + level.iconcapture3d = "waypoint_grab_red"; + level.iconcapture2d = "waypoint_grab_red"; + level.icondefend3d = "waypoint_defend_flag"; + level.icondefend2d = "waypoint_defend_flag"; + level.icondropped3d = "waypoint_defend_flag"; + level.icondropped2d = "waypoint_defend_flag"; + level.iconreturn3d = "waypoint_return_flag"; + level.iconreturn2d = "waypoint_return_flag"; + level.iconbase3d = "waypoint_defend_flag"; + level.iconescort3d = "waypoint_escort"; + level.iconescort2d = "waypoint_escort"; + level.iconkill3d = "waypoint_kill"; + level.iconkill2d = "waypoint_kill"; + level.iconwaitforflag3d = "waypoint_waitfor_flag"; + precacheshader( level.iconcapture3d ); + precacheshader( level.iconcapture2d ); + precacheshader( level.icondefend3d ); + precacheshader( level.icondefend2d ); + precacheshader( level.icondropped3d ); + precacheshader( level.icondropped2d ); + precacheshader( level.iconbase3d ); + precacheshader( level.iconreturn3d ); + precacheshader( level.iconreturn2d ); + precacheshader( level.iconescort3d ); + precacheshader( level.iconescort2d ); + precacheshader( level.iconkill3d ); + precacheshader( level.iconkill2d ); + precacheshader( level.iconwaitforflag3d ); + level.flagbasefxid = []; + level.flagbasefxid[ "allies" ] = loadfx( "misc/fx_ui_oneflag_flagbase" ); + level.flagbasefxid[ "axis" ] = loadfx( "misc/fx_ui_oneflag_flagbase" ); + level.flag_zones = getentarray( "ctf_flag_zone_trig", "targetname" ); + flag_triggers = getentarray( "ctf_flag_pickup_trig", "targetname" ); + if ( !isDefined( flag_triggers ) || flag_triggers.size != 2 ) + { +/# + maps/mp/_utility::error( "Not enough ctf_flag_pickup_trig triggers found in map. Need two." ); +#/ + return; + } + index = 0; + while ( index < flag_triggers.size ) + { + trigger = flag_triggers[ index ]; + flag = createflag( trigger ); + team = flag maps/mp/gametypes/_gameobjects::getownerteam(); + level.flags[ level.flags.size ] = flag; + level.teamflags[ team ] = flag; + index++; + } + primaryflags = getentarray( "flag_primary", "targetname" ); + secondaryflags = getentarray( "flag_secondary", "targetname" ); + domflags = []; + index = 0; + while ( index < primaryflags.size ) + { + domflags[ domflags.size ] = primaryflags[ index ]; + index++; + } + index = 0; + while ( index < secondaryflags.size ) + { + domflags[ domflags.size ] = secondaryflags[ index ]; + index++; + } + index = 0; + while ( index < domflags.size ) + { + trigger = domflags[ index ]; + if ( trigger.script_label == "_b" ) + { + level.neutralflagorigin = trigger.origin; + neutraltrigger = spawn( "trigger_radius", level.neutralflagorigin, 0, 30, 100 ); + flag = createflag( neutraltrigger ); + level.neutralflag = flag; + flag maps/mp/gametypes/_gameobjects::allowcarry( "any" ); + } + index++; + } + flag_zones = getentarray( "ctf_flag_zone_trig", "targetname" ); + if ( !isDefined( flag_zones ) || flag_zones.size != 2 ) + { +/# + maps/mp/_utility::error( "Not enough ctf_flag_zone_trig triggers found in map. Need two." ); +#/ + return; + } + index = 0; + while ( index < flag_zones.size ) + { + trigger = flag_zones[ index ]; + flagzone = createflagzone( trigger ); + team = flagzone maps/mp/gametypes/_gameobjects::getownerteam(); + level.flagzones[ level.flagzones.size ] = flagzone; + level.teamflagzones[ team ] = flagzone; + level.flaghints[ team ] = createflaghint( team, trigger.origin ); + facing_angle = getDvarInt( "scr_ctf_spawnPointFacingAngle" ); + setspawnpointsbaseweight( getotherteamsmask( team ), trigger.origin, facing_angle, level.spawnsystem.objective_facing_bonus ); + index++; + } + createreturnmessageelems(); +} + +ctf_icon_hide() +{ + level waittill( "game_ended" ); + level.teamflags[ "allies" ] maps/mp/gametypes/_gameobjects::setvisibleteam( "none" ); + level.teamflags[ "axis" ] maps/mp/gametypes/_gameobjects::setvisibleteam( "none" ); +} + +removeinfluencers() +{ + if ( isDefined( self.spawn_influencer_enemy_carrier ) ) + { + removeinfluencer( self.spawn_influencer_enemy_carrier ); + self.spawn_influencer_enemy_carrier = undefined; + } + if ( isDefined( self.spawn_influencer_friendly_carrier ) ) + { + removeinfluencer( self.spawn_influencer_friendly_carrier ); + self.spawn_influencer_friendly_carrier = undefined; + } + if ( isDefined( self.spawn_influencer_dropped ) ) + { + removeinfluencer( self.spawn_influencer_dropped ); + self.spawn_influencer_dropped = undefined; + } +} + +ondrop( player ) +{ + if ( isDefined( player ) ) + { + player clearclientflag( 0 ); + } + _a825 = level.flagzones; + _k825 = getFirstArrayKey( _a825 ); + while ( isDefined( _k825 ) ) + { + goal = _a825[ _k825 ]; + goal maps/mp/gametypes/_gameobjects::setflags( 0 ); + _k825 = getNextArrayKey( _a825, _k825 ); + } + otherteam = self maps/mp/gametypes/_gameobjects::getownerteam(); + team = getotherteam( otherteam ); + self.ownerteam = "neutral"; + bbprint( "mpobjective", "gametime %d objtype %s team %s", getTime(), "ctf_flagdropped", team ); + self.visuals[ 0 ] setclientflag( 6 ); + self.visuals[ 0 ] setmodel( maps/mp/teams/_teams::getteamflagmodel( "neutral" ) ); + if ( level.touchreturn ) + { + self maps/mp/gametypes/_gameobjects::allowcarry( "any" ); + level.flaghints[ otherteam ] turn_off(); + } + if ( isDefined( player ) ) + { + printandsoundoneveryone( team, undefined, &"", undefined, "mp_war_objective_lost" ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_NEUTRAL_FLAG_DROPPED", player, team ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_NEUTRAL_FLAG_DROPPED", player, otherteam ); + } + else + { + printandsoundoneveryone( team, undefined, &"", undefined, "mp_war_objective_lost" ); + } + maps/mp/gametypes/_globallogic_audio::leaderdialog( "wedrop_flag", otherteam, "ctf_flag" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "theydrop_flag", team, "ctf_flag_enemy" ); + if ( isDefined( player ) ) + { + player logstring( team + " flag dropped" ); + } + else + { + logstring( team + " flag dropped" ); + } + if ( isDefined( player ) ) + { + player playlocalsound( "mpl_flag_drop_plr" ); + } + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagdrop_sting_friend", otherteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagdrop_sting_enemy", team ); + if ( level.touchreturn ) + { + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.iconreturn3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.iconreturn2d ); + } + else + { + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.icondropped3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.icondropped2d ); + } + self maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconcapture3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconcapture2d ); + thread maps/mp/_utility::playsoundonplayers( game[ "flag_dropped_sound" ], game[ "attackers" ] ); + self thread returnflagaftertimemsg( level.idleflagreturntime ); + if ( isDefined( player ) ) + { + self removeinfluencers(); + } + else + { + self.spawn_influencer_friendly_carrier = undefined; + self.spawn_influencer_enemy_carrier = undefined; + } + ss = level.spawnsystem; + player_team_mask = getteammask( otherteam ); + enemy_team_mask = getteammask( team ); + if ( isDefined( player ) ) + { + flag_origin = player.origin; + } + else + { + flag_origin = self.curorigin; + } + self.spawn_influencer_dropped = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, flag_origin, ss.ctf_dropped_influencer_radius, ss.ctf_dropped_influencer_score, player_team_mask | enemy_team_mask, "ctf_flag_dropped,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ss.ctf_dropped_influencer_score_curve ), level.idleflagreturntime, self.trigger ); +} + +onpickup( player ) +{ + carrierkilledby = self.carrierkilledby; + self.carrierkilledby = undefined; + if ( isDefined( self.spawn_influencer_dropped ) ) + { + removeinfluencer( self.spawn_influencer_dropped ); + self.spawn_influencer_dropped = undefined; + } + player addplayerstatwithgametype( "PICKUPS", 1 ); + self.ownerteam = player.team; + _a945 = level.flagzones; + _k945 = getFirstArrayKey( _a945 ); + while ( isDefined( _k945 ) ) + { + goal = _a945[ _k945 ]; + if ( goal.ownerteam != player.team ) + { + goal maps/mp/gametypes/_gameobjects::setflags( 1 ); + } + _k945 = getNextArrayKey( _a945, _k945 ); + } + if ( level.touchreturn ) + { + self maps/mp/gametypes/_gameobjects::allowcarry( "enemy" ); + } + self removeinfluencers(); + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + otherteam = getotherteam( team ); + player maps/mp/gametypes/_weapons::detach_all_weapons(); + self maps/mp/gametypes/_gameobjects::setvisiblecarriermodel( maps/mp/teams/_teams::getteamflagcarrymodel( player.pers[ "team" ] ) ); + self maps/mp/gametypes/_gameobjects::setcarryicon( maps/mp/teams/_teams::getteamflagicon( player.pers[ "team" ] ) ); + player maps/mp/gametypes/_weapons::forcestowedweaponupdate(); + bbprint( "mpobjective", "gametime %d objtype %s team %s", getTime(), "ctf_flagpickup", team ); + player recordgameevent( "pickup" ); + maps/mp/_scoreevents::processscoreevent( "flag_grab", player ); + maps/mp/_demo::bookmark( "event", getTime(), player ); + printandsoundoneveryone( otherteam, undefined, &"", undefined, "mp_obj_taken", "mp_enemy_obj_taken" ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_NEUTRAL_FLAG_TAKEN", player, otherteam ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_NEUTRAL_FLAG_TAKEN", player, team ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "wetake_flag", team, "ctf_flag" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "theytake_flag", otherteam, "ctf_flag_enemy" ); + player.isflagcarrier = 1; + player.flagcarried = self; + player playlocalsound( "mpl_flag_pickup_plr" ); + player setclientflag( 0 ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagget_sting_friend", otherteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagget_sting_enemy", team ); + if ( level.enemycarriervisible ) + { + self maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + } + else + { + self maps/mp/gametypes/_gameobjects::setvisibleteam( "enemy" ); + } + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.iconkill2d ); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.iconkill3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconescort2d ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconescort3d ); + player thread claim_trigger( level.flaghints[ otherteam ] ); + update_hints(); + player logstring( team + " flag taken" ); + ss = level.spawnsystem; + player_team_mask = getteammask( otherteam ); + enemy_team_mask = getteammask( team ); + self.spawn_influencer_enemy_carrier = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, player.origin, ss.ctf_enemy_carrier_influencer_radius, ss.ctf_enemy_carrier_influencer_score, enemy_team_mask, "ctf_flag_enemy_carrier,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ss.ctf_enemy_carrier_influencer_score_curve ), 0, player ); + self.spawn_influencer_friendly_carrier = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, player.origin, ss.ctf_friendly_carrier_influencer_radius, ss.ctf_friendly_carrier_influencer_score, player_team_mask, "ctf_flag_friendly_carrier,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ss.ctf_friendly_carrier_influencer_score_curve ), 0, player ); +} + +watchforscore() +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "disconnect" ); + while ( 1 ) + { + self.trigger waittill( "trigger", player ); + if ( self.ownerteam != player.team && isDefined( player.carryobject ) ) + { + flag = player.carryobject; + flag oncapture( player ); + flag.ownerteam = "neutral"; + flag maps/mp/gametypes/_gameobjects::allowcarry( "none" ); + flag maps/mp/gametypes/_gameobjects::setvisibleteam( "none" ); + flag maps/mp/gametypes/_gameobjects::returnhome(); + flag.visuals[ 0 ] hide(); + _a1063 = level.flags; + _k1063 = getFirstArrayKey( _a1063 ); + while ( isDefined( _k1063 ) ) + { + baseflag = _a1063[ _k1063 ]; + baseflag.visuals[ 0 ] hide(); + _k1063 = getNextArrayKey( _a1063, _k1063 ); + } + _a1067 = level.flagzones; + _k1067 = getFirstArrayKey( _a1067 ); + while ( isDefined( _k1067 ) ) + { + goal = _a1067[ _k1067 ]; + goal maps/mp/gametypes/_gameobjects::setflags( 0 ); + _k1067 = getNextArrayKey( _a1067, _k1067 ); + } + level.oneflagtimer.label = game[ "strings" ][ "flag_respawning_in" ]; + level.oneflagtimer settimer( level.flagrespawntime ); + wait 1; + level.oneflagtimer.alpha = 1; + wait ( level.flagrespawntime - 1 ); + level.oneflagtimer.alpha = 0; + flag maps/mp/gametypes/_gameobjects::allowcarry( "any" ); + flag maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + flag.visuals[ 0 ] show(); + } + } +} + +onpickupmusicstate( player ) +{ + self endon( "disconnect" ); + self endon( "death" ); + wait 6; + if ( player.isflagcarrier ) + { + } +} + +ishome() +{ + if ( isDefined( self.carrier ) ) + { + return 0; + } + if ( self.curorigin != self.trigger.baseorigin ) + { + return 0; + } + return 1; +} + +returnflag() +{ + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + otherteam = getotherteam( team ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagreturn_sting", team ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagreturn_sting", otherteam ); + level.teamflagzones[ otherteam ] maps/mp/gametypes/_gameobjects::allowuse( "friendly" ); + level.teamflagzones[ otherteam ] maps/mp/gametypes/_gameobjects::setvisibleteam( "friendly" ); + update_hints(); + if ( level.touchreturn ) + { + self maps/mp/gametypes/_gameobjects::allowcarry( "enemy" ); + } + self maps/mp/gametypes/_gameobjects::returnhome(); + self maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.icondefend3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.icondefend2d ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconcapture3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconcapture2d ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "wereturn_flag", team, "ctf_flag_enemy" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "theyreturn_flag", otherteam, "ctf_flag" ); +} + +oncapture( player ) +{ + team = player.pers[ "team" ]; + enemyteam = getotherteam( team ); + time = getTime(); + playerteamsflag = level.teamflags[ team ]; + if ( playerteamsflag maps/mp/gametypes/_gameobjects::isobjectawayfromhome() ) + { + return; + } + printandsoundoneveryone( team, undefined, &"", undefined, "mp_obj_captured", "mp_enemy_obj_captured" ); + bbprint( "mpobjective", "gametime %d objtype %s team %s", time, "ctf_flagcapture", enemyteam ); + game[ "challenge" ][ team ][ "capturedFlag" ] = 1; + player maps/mp/_challenges::capturedobjective( time ); + if ( isDefined( player.pers[ "captures" ] ) ) + { + player.pers[ "captures" ]++; + player.captures = player.pers[ "captures" ]; + } + maps/mp/_demo::bookmark( "event", getTime(), player ); + player addplayerstatwithgametype( "CAPTURES", 1 ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_NEUTRAL_FLAG_CAPTURED", player, team ); + level thread maps/mp/_popups::displayteammessagetoteam( &"MP_NEUTRAL_FLAG_CAPTURED", player, enemyteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagcapture_sting_enemy", enemyteam ); + maps/mp/gametypes/_globallogic_audio::play_2d_on_team( "mpl_flagcapture_sting_friend", team ); + player giveflagcapturexp( player ); + player logstring( enemyteam + " flag captured" ); + flag = player.carryobject; + flag.dontannouncereturn = 1; + flag maps/mp/gametypes/_gameobjects::returnhome(); + flag.dontannouncereturn = undefined; + otherteam = getotherteam( team ); + level.teamflags[ otherteam ] maps/mp/gametypes/_gameobjects::returnhome(); + level.teamflags[ team ] maps/mp/gametypes/_gameobjects::returnhome(); + player.isflagcarrier = 0; + player.flagcarried = undefined; + player clearclientflag( 0 ); + maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( team, 1 ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "wecap_flag", team, "ctf_flag" ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "theycap_flag", enemyteam, "ctf_flag_enemy" ); + flag removeinfluencers(); +} + +giveflagcapturexp( player ) +{ + maps/mp/_scoreevents::processscoreevent( "flag_capture", player ); + player recordgameevent( "capture" ); +} + +onreset() +{ + update_hints(); + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", level.icondefend3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "friendly", level.icondefend2d ); + self maps/mp/gametypes/_gameobjects::set3dicon( "enemy", level.iconcapture3d ); + self maps/mp/gametypes/_gameobjects::set2dicon( "enemy", level.iconcapture2d ); + self.visuals[ 0 ] clearclientflag( 6 ); +} + +getotherflag( flag ) +{ + if ( flag == level.flags[ 0 ] ) + { + return level.flags[ 1 ]; + } + return level.flags[ 0 ]; +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + flagteam = "invalidTeam"; + inflagzone = 0; + defendedflag = 0; + offendedflag = 0; + flagcarrier = level.neutralflag.carrier; + if ( isDefined( flagcarrier ) ) + { + flagorigin = level.neutralflag.carrier.origin; + iscarried = 1; + if ( isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + if ( isDefined( level.neutralflag.carrier.attackerdata ) ) + { + if ( level.neutralflag.carrier != attacker ) + { + if ( isDefined( level.neutralflag.carrier.attackerdata[ self.clientid ] ) ) + { + maps/mp/_scoreevents::processscoreevent( "rescue_flag_carrier", attacker, undefined, sweapon ); + } + } + } + } + } + else + { + flagorigin = level.neutralflag.curorigin; + iscarried = 0; + } + dist = distance2d( self.origin, flagorigin ); + if ( dist < level.defaultoffenseradius ) + { + inflagzone = 1; + if ( level.neutralflag.ownerteam == attacker.pers[ "team" ] ) + { + offendedflag = 1; + } + else + { + defendedflag = 1; + } + } + dist = distance2d( attacker.origin, flagorigin ); + if ( dist < level.defaultoffenseradius ) + { + inflagzone = 1; + if ( level.neutralflag.ownerteam == attacker.pers[ "team" ] ) + { + offendedflag = 1; + } + else + { + defendedflag = 1; + } + } + if ( inflagzone && isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + if ( defendedflag ) + { + attacker.pers[ "defends" ]++; + attacker.defends = attacker.pers[ "defends" ]; + attacker addplayerstatwithgametype( "DEFENDS", 1 ); + if ( isDefined( self.isflagcarrier ) && self.isflagcarrier ) + { + maps/mp/_scoreevents::processscoreevent( "kill_flag_carrier", attacker, undefined, sweapon ); + } + else + { + maps/mp/_scoreevents::processscoreevent( "killed_attacker", attacker, undefined, sweapon ); + } + self recordkillmodifier( "assaulting" ); + } + if ( offendedflag ) + { + attacker addplayerstatwithgametype( "OFFENDS", 1 ); + if ( iscarried == 1 ) + { + if ( isDefined( flagcarrier ) && attacker == flagcarrier ) + { + maps/mp/_scoreevents::processscoreevent( "killed_enemy_while_carrying_flag", attacker, undefined, sweapon ); + } + else + { + maps/mp/_scoreevents::processscoreevent( "defend_flag_carrier", attacker, undefined, sweapon ); + } + } + else + { + maps/mp/_scoreevents::processscoreevent( "killed_defender", attacker, undefined, sweapon ); + } + self recordkillmodifier( "defending" ); + } + } + } + if ( !isDefined( self.isflagcarrier ) || !self.isflagcarrier ) + { + return; + } + if ( isDefined( attacker ) && isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + while ( isDefined( self.flagcarried ) ) + { + index = 0; + while ( index < level.flags.size ) + { + currentflag = level.flags[ index ]; + if ( currentflag.ownerteam == self.team ) + { + if ( currentflag.curorigin == currentflag.trigger.baseorigin ) + { + dist = distance2d( self.origin, currentflag.curorigin ); + if ( dist < level.defaultoffenseradius ) + { + self.flagcarried.carrierkilledby = attacker; + break; + } + } + } + else + { + index++; + } + } + } + attacker recordgameevent( "kill_carrier" ); + self recordkillmodifier( "carrying" ); + } +} + +createreturnmessageelems() +{ + level.returnmessageelems = []; + level.returnmessageelems[ "allies" ][ "axis" ] = createservertimer( "objective", 1,4, "allies" ); + level.returnmessageelems[ "allies" ][ "axis" ] setpoint( "TOPRIGHT", "TOPRIGHT", 0, 0 ); + level.returnmessageelems[ "allies" ][ "axis" ].label = &"MP_ENEMY_FLAG_RETURNING_IN"; + level.returnmessageelems[ "allies" ][ "axis" ].alpha = 0; + level.returnmessageelems[ "allies" ][ "axis" ].archived = 0; + level.returnmessageelems[ "allies" ][ "allies" ] = createservertimer( "objective", 1,4, "allies" ); + level.returnmessageelems[ "allies" ][ "allies" ] setpoint( "TOPRIGHT", "TOPRIGHT", 0, 20 ); + level.returnmessageelems[ "allies" ][ "allies" ].label = &"MP_YOUR_FLAG_RETURNING_IN"; + level.returnmessageelems[ "allies" ][ "allies" ].alpha = 0; + level.returnmessageelems[ "allies" ][ "allies" ].archived = 0; + level.returnmessageelems[ "axis" ][ "allies" ] = createservertimer( "objective", 1,4, "axis" ); + level.returnmessageelems[ "axis" ][ "allies" ] setpoint( "TOPRIGHT", "TOPRIGHT", 0, 0 ); + level.returnmessageelems[ "axis" ][ "allies" ].label = &"MP_ENEMY_FLAG_RETURNING_IN"; + level.returnmessageelems[ "axis" ][ "allies" ].alpha = 0; + level.returnmessageelems[ "axis" ][ "allies" ].archived = 0; + level.returnmessageelems[ "axis" ][ "axis" ] = createservertimer( "objective", 1,4, "axis" ); + level.returnmessageelems[ "axis" ][ "axis" ] setpoint( "TOPRIGHT", "TOPRIGHT", 0, 20 ); + level.returnmessageelems[ "axis" ][ "axis" ].label = &"MP_YOUR_FLAG_RETURNING_IN"; + level.returnmessageelems[ "axis" ][ "axis" ].alpha = 0; + level.returnmessageelems[ "axis" ][ "axis" ].archived = 0; +} + +returnflagaftertimemsg( time ) +{ + if ( level.touchreturn || level.idleflagreturntime == 0 ) + { + return; + } + self notify( "returnFlagAfterTimeMsg" ); + self endon( "returnFlagAfterTimeMsg" ); + result = returnflaghudelems( time ); + self removeinfluencers(); + self clearreturnflaghudelems(); + if ( !isDefined( result ) ) + { + return; + } +} + +returnflaghudelems( time ) +{ + self endon( "picked_up" ); + level endon( "game_ended" ); + ownerteam = self maps/mp/gametypes/_gameobjects::getownerteam(); +/# + assert( !level.returnmessageelems[ "axis" ][ ownerteam ].alpha ); +#/ + level.returnmessageelems[ "axis" ][ ownerteam ].alpha = 1; + level.returnmessageelems[ "axis" ][ ownerteam ] settimer( time ); +/# + assert( !level.returnmessageelems[ "allies" ][ ownerteam ].alpha ); +#/ + level.returnmessageelems[ "allies" ][ ownerteam ].alpha = 1; + level.returnmessageelems[ "allies" ][ ownerteam ] settimer( time ); + if ( time <= 0 ) + { + return 0; + } + else + { + wait time; + } + return 1; +} + +clearreturnflaghudelems() +{ + ownerteam = self maps/mp/gametypes/_gameobjects::getownerteam(); + level.returnmessageelems[ "allies" ][ ownerteam ].alpha = 0; + level.returnmessageelems[ "axis" ][ ownerteam ].alpha = 0; +} + +resetflagbaseeffect() +{ + wait 0,1; + if ( isDefined( self.baseeffect ) ) + { + self.baseeffect delete(); + } + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + if ( team != "axis" && team != "allies" ) + { + return; + } + fxid = level.flagbasefxid[ team ]; + self.baseeffect = spawnfx( fxid, self.baseeffectpos, self.baseeffectforward, self.baseeffectright ); + triggerfx( self.baseeffect ); +} + +turn_on() +{ + if ( level.hardcoremode ) + { + return; + } + self.origin = self.original_origin; +} + +turn_off() +{ + self.origin = ( self.original_origin[ 0 ], self.original_origin[ 1 ], self.original_origin[ 2 ] - 10000 ); +} + +update_hints() +{ + allied_flag = level.teamflags[ "allies" ]; + axis_flag = level.teamflags[ "axis" ]; + if ( !level.touchreturn ) + { + return; + } + if ( isDefined( allied_flag.carrier ) && axis_flag maps/mp/gametypes/_gameobjects::isobjectawayfromhome() ) + { + level.flaghints[ "axis" ] turn_on(); + } + else + { + level.flaghints[ "axis" ] turn_off(); + } + if ( isDefined( axis_flag.carrier ) && allied_flag maps/mp/gametypes/_gameobjects::isobjectawayfromhome() ) + { + level.flaghints[ "allies" ] turn_on(); + } + else + { + level.flaghints[ "allies" ] turn_off(); + } +} + +claim_trigger( trigger ) +{ + self endon( "disconnect" ); + self clientclaimtrigger( trigger ); + self waittill( "drop_object" ); + self clientreleasetrigger( trigger ); +} + +createflagspawninfluencer( entityteam ) +{ + ctf_friendly_base_influencer_score = level.spawnsystem.ctf_friendly_base_influencer_score; + ctf_friendly_base_influencer_score_curve = level.spawnsystem.ctf_friendly_base_influencer_score_curve; + ctf_friendly_base_influencer_radius = level.spawnsystem.ctf_friendly_base_influencer_radius; + ctf_enemy_base_influencer_score = level.spawnsystem.ctf_enemy_base_influencer_score; + ctf_enemy_base_influencer_score_curve = level.spawnsystem.ctf_enemy_base_influencer_score_curve; + ctf_enemy_base_influencer_radius = level.spawnsystem.ctf_enemy_base_influencer_radius; + otherteam = getotherteam( entityteam ); + team_mask = getteammask( entityteam ); + other_team_mask = getteammask( otherteam ); + self.spawn_influencer_friendly = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.trigger.origin, ctf_friendly_base_influencer_radius, ctf_friendly_base_influencer_score, team_mask, "ctf_friendly_base,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ctf_friendly_base_influencer_score_curve ) ); + self.spawn_influencer_enemy = addsphereinfluencer( level.spawnsystem.einfluencer_type_game_mode, self.trigger.origin, ctf_enemy_base_influencer_radius, ctf_enemy_base_influencer_score, other_team_mask, "ctf_enemy_base,r,s", maps/mp/gametypes/_spawning::get_score_curve_index( ctf_enemy_base_influencer_score_curve ) ); +} + +ctf_gamemodespawndvars( reset_dvars ) +{ + ss = level.spawnsystem; + ss.ctf_friendly_base_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_friendly_base_influencer_score", "0", reset_dvars ); + ss.ctf_friendly_base_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_friendly_base_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_friendly_base_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_friendly_base_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.ctf_enemy_base_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_enemy_base_influencer_score", "-500", reset_dvars ); + ss.ctf_enemy_base_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_enemy_base_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_enemy_base_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_enemy_base_influencer_radius", "" + ( 15 * get_player_height() ), reset_dvars ); + ss.ctf_enemy_carrier_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_enemy_carrier_influencer_score", "0", reset_dvars ); + ss.ctf_enemy_carrier_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_enemy_carrier_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_enemy_carrier_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_enemy_carrier_influencer_radius", "" + ( 10 * get_player_height() ), reset_dvars ); + ss.ctf_friendly_carrier_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_friendly_carrier_influencer_score", "0", reset_dvars ); + ss.ctf_friendly_carrier_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_friendly_carrier_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_friendly_carrier_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_friendly_carrier_influencer_radius", "" + ( 8 * get_player_height() ), reset_dvars ); + ss.ctf_dropped_influencer_score = set_dvar_float_if_unset( "scr_spawn_ctf_dropped_influencer_score", "0", reset_dvars ); + ss.ctf_dropped_influencer_score_curve = set_dvar_if_unset( "scr_spawn_ctf_dropped_influencer_score_curve", "constant", reset_dvars ); + ss.ctf_dropped_influencer_radius = set_dvar_float_if_unset( "scr_spawn_ctf_dropped_influencer_radius", "" + ( 10 * get_player_height() ), reset_dvars ); +} + +ctf_getteamkillpenalty( einflictor, attacker, smeansofdeath, sweapon ) +{ + teamkill_penalty = maps/mp/gametypes/_globallogic_defaults::default_getteamkillpenalty( einflictor, attacker, smeansofdeath, sweapon ); + if ( isDefined( self.isflagcarrier ) && self.isflagcarrier ) + { + teamkill_penalty *= level.teamkillpenaltymultiplier; + } + return teamkill_penalty; +} + +ctf_getteamkillscore( einflictor, attacker, smeansofdeath, sweapon ) +{ + teamkill_score = maps/mp/gametypes/_rank::getscoreinfovalue( "kill" ); + if ( isDefined( self.isflagcarrier ) && self.isflagcarrier ) + { + teamkill_score *= level.teamkillscoremultiplier; + } + return int( teamkill_score ); +} diff --git a/patch_mp/maps/mp/gametypes/sas.gsc b/patch_mp/maps/mp/gametypes/sas.gsc new file mode 100644 index 0000000..6b762a4 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/sas.gsc @@ -0,0 +1,273 @@ +#include maps/mp/gametypes/_persistence; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_wager; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +main() +{ + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 5000 ); + registerroundlimit( 0, 10 ); + registerroundwinlimit( 0, 10 ); + registernumlives( 0, 100 ); + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onplayerdamage = ::onplayerdamage; + level.onplayerkilled = ::onplayerkilled; + level.onwagerawards = ::onwagerawards; + level.pointsperprimarykill = getgametypesetting( "pointsPerPrimaryKill" ); + level.pointspersecondarykill = getgametypesetting( "pointsPerSecondaryKill" ); + level.pointsperprimarygrenadekill = getgametypesetting( "pointsPerPrimaryGrenadeKill" ); + level.pointspermeleekill = getgametypesetting( "pointsPerMeleeKill" ); + level.setbacks = getgametypesetting( "setbacks" ); + switch( getgametypesetting( "gunSelection" ) ) + { + case 0: + level.setbackweapon = undefined; + break; + case 1: + level.setbackweapon = getreffromitemindex( getbaseweaponitemindex( "hatchet_mp" ) ) + "_mp"; + break; + case 2: + level.setbackweapon = getreffromitemindex( getbaseweaponitemindex( "crossbow_mp" ) ) + "_mp"; + break; + case 3: + level.setbackweapon = getreffromitemindex( getbaseweaponitemindex( "knife_ballistic_mp" ) ) + "_mp"; + break; + default: +/# + assert( 1, "Invalid setting for gunSelection" ); +#/ + break; + } + game[ "dialog" ][ "gametype" ] = "sns_start"; + game[ "dialog" ][ "wm_humiliation" ] = "mpl_wager_bankrupt"; + game[ "dialog" ][ "wm_humiliated" ] = "sns_hum"; + level.givecustomloadout = ::givecustomloadout; + precachestring( &"MP_HUMILIATION" ); + precachestring( &"MP_HUMILIATED" ); + precachestring( &"MP_BANKRUPTED" ); + precachestring( &"MP_BANKRUPTED_OTHER" ); + precacheshader( "hud_acoustic_sensor" ); + precacheshader( "hud_us_stungrenade" ); + setscoreboardcolumns( "pointstowin", "kills", "deaths", "tomahawks", "humiliated" ); +} + +givecustomloadout() +{ + self notify( "sas_spectator_hud" ); + defaultweapon = "crossbow_mp"; + self maps/mp/gametypes/_wager::setupblankrandomplayer( 1, 1, defaultweapon ); + self giveweapon( defaultweapon ); + self setweaponammoclip( defaultweapon, 3 ); + self setweaponammostock( defaultweapon, 3 ); + secondaryweapon = "knife_ballistic_mp"; + self giveweapon( secondaryweapon ); + self setweaponammostock( secondaryweapon, 2 ); + offhandprimary = "hatchet_mp"; + self setoffhandprimaryclass( offhandprimary ); + self giveweapon( offhandprimary ); + self setweaponammoclip( offhandprimary, 1 ); + self setweaponammostock( offhandprimary, 1 ); + self giveweapon( "knife_mp" ); + self switchtoweapon( defaultweapon ); + self setspawnweapon( defaultweapon ); + self.killswithsecondary = 0; + self.killswithprimary = 0; + self.killswithbothawarded = 0; + return defaultweapon; +} + +onplayerdamage( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime ) +{ + if ( sweapon == "crossbow_mp" && smeansofdeath == "MOD_IMPACT" ) + { + if ( isDefined( eattacker ) && isplayer( eattacker ) ) + { + if ( !isDefined( eattacker.pers[ "sticks" ] ) ) + { + eattacker.pers[ "sticks" ] = 1; + } + else + { + eattacker.pers[ "sticks" ]++; + } + eattacker.sticks = eattacker.pers[ "sticks" ]; + } + } + return idamage; +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( isDefined( attacker ) && isplayer( attacker ) && attacker != self ) + { + baseweaponname = getreffromitemindex( getbaseweaponitemindex( sweapon ) ) + "_mp"; + if ( smeansofdeath == "MOD_MELEE" ) + { + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.pointspermeleekill ); + } + else if ( baseweaponname == "crossbow_mp" ) + { + attacker.killswithprimary++; + if ( attacker.killswithbothawarded == 0 && attacker.killswithsecondary > 0 ) + { + attacker.killswithbothawarded = 1; + maps/mp/_scoreevents::processscoreevent( "kill_with_crossbow_and_ballistic_sas", attacker, self, sweapon ); + } + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.pointsperprimarykill ); + } + else if ( baseweaponname == "hatchet_mp" ) + { + if ( maps/mp/gametypes/_globallogic::istopscoringplayer( self ) ) + { + maps/mp/_scoreevents::processscoreevent( "kill_leader_with_axe_sas", attacker, self, sweapon ); + } + else + { + maps/mp/_scoreevents::processscoreevent( "kill_with_axe_sas", attacker, self, sweapon ); + } + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.pointsperprimarygrenadekill ); + } + else + { + if ( baseweaponname == "knife_ballistic_mp" ) + { + attacker.killswithsecondary++; + if ( attacker.killswithbothawarded == 0 && attacker.killswithprimary > 0 ) + { + attacker.killswithbothawarded = 1; + maps/mp/_scoreevents::processscoreevent( "kill_with_crossbow_and_ballistic_sas", attacker, self, sweapon ); + } + } + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.pointspersecondarykill ); + } + if ( isDefined( level.setbackweapon ) && baseweaponname == level.setbackweapon ) + { + self.pers[ "humiliated" ]++; + self.humiliated = self.pers[ "humiliated" ]; + if ( level.setbacks == 0 ) + { + self maps/mp/gametypes/_globallogic_score::setpointstowin( 0 ); + } + else + { + self maps/mp/gametypes/_globallogic_score::givepointstowin( level.setbacks * -1 ); + } + attacker playlocalsound( game[ "dialog" ][ "wm_humiliation" ] ); + self playlocalsound( game[ "dialog" ][ "wm_humiliation" ] ); + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "wm_humiliated" ); + } + } + else + { + self.pers[ "humiliated" ]++; + self.humiliated = self.pers[ "humiliated" ]; + if ( level.setbacks == 0 ) + { + self maps/mp/gametypes/_globallogic_score::setpointstowin( 0 ); + } + else + { + self maps/mp/gametypes/_globallogic_score::givepointstowin( level.setbacks * -1 ); + } + self thread maps/mp/gametypes/_wager::queuewagerpopup( &"MP_HUMILIATED", 0, &"MP_BANKRUPTED", "wm_humiliated" ); + self playlocalsound( game[ "dialog" ][ "wm_humiliated" ] ); + } +} + +onstartgametype() +{ + setdvar( "scr_xpscale", 0 ); + setclientnamemode( "auto_change" ); + setobjectivetext( "allies", &"OBJECTIVES_SAS" ); + setobjectivetext( "axis", &"OBJECTIVES_SAS" ); + if ( level.splitscreen ) + { + setobjectivescoretext( "allies", &"OBJECTIVES_SAS" ); + setobjectivescoretext( "axis", &"OBJECTIVES_SAS" ); + } + else + { + setobjectivescoretext( "allies", &"OBJECTIVES_SAS_SCORE" ); + setobjectivescoretext( "axis", &"OBJECTIVES_SAS_SCORE" ); + } + setobjectivehinttext( "allies", &"OBJECTIVES_SAS_HINT" ); + setobjectivehinttext( "axis", &"OBJECTIVES_SAS_HINT" ); + allowed[ 0 ] = "sas"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 0 ); + level.spawnmaxs = ( 0, 0, 0 ); + newspawns = getentarray( "mp_wager_spawn", "classname" ); + if ( newspawns.size > 0 ) + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_wager_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_wager_spawn" ); + } + else + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_dm_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_dm_spawn" ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.usestartspawns = 0; + level.displayroundendtext = 0; + if ( isDefined( game[ "roundsplayed" ] ) && game[ "roundsplayed" ] > 0 ) + { + } +} + +onspawnplayerunified() +{ + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( self.pers[ "team" ] ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_dm( spawnpoints ); + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "sas" ); + } +} + +onwagerawards() +{ + tomahawks = self maps/mp/gametypes/_globallogic_score::getpersstat( "tomahawks" ); + if ( !isDefined( tomahawks ) ) + { + tomahawks = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", tomahawks, 0 ); + sticks = self maps/mp/gametypes/_globallogic_score::getpersstat( "sticks" ); + if ( !isDefined( sticks ) ) + { + sticks = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", sticks, 1 ); + bestkillstreak = self maps/mp/gametypes/_globallogic_score::getpersstat( "best_kill_streak" ); + if ( !isDefined( bestkillstreak ) ) + { + bestkillstreak = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", bestkillstreak, 2 ); +} diff --git a/patch_mp/maps/mp/gametypes/sd.gsc b/patch_mp/maps/mp/gametypes/sd.gsc new file mode 100644 index 0000000..4e30d39 --- /dev/null +++ b/patch_mp/maps/mp/gametypes/sd.gsc @@ -0,0 +1,997 @@ +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/gametypes/_globallogic_utils; +#include maps/mp/_demo; +#include maps/mp/_popups; +#include maps/mp/gametypes/_battlechatter_mp; +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_spectating; +#include maps/mp/_medals; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_rank; +#include maps/mp/gametypes/_globallogic_defaults; +#include maps/mp/gametypes/_hud_util; +#include common_scripts/utility; + +main() +{ + if ( getDvar( "mapname" ) == "mp_background" ) + { + return; + } + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registerroundswitch( 0, 9 ); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 500 ); + registerroundlimit( 0, 12 ); + registerroundwinlimit( 0, 10 ); + registernumlives( 0, 100 ); + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + level.teambased = 1; + level.overrideteamscore = 1; + level.onprecachegametype = ::onprecachegametype; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.playerspawnedcb = ::sd_playerspawnedcb; + level.onplayerkilled = ::onplayerkilled; + level.ondeadevent = ::ondeadevent; + level.ononeleftevent = ::ononeleftevent; + level.ontimelimit = ::ontimelimit; + level.onroundswitch = ::onroundswitch; + level.getteamkillpenalty = ::sd_getteamkillpenalty; + level.getteamkillscore = ::sd_getteamkillscore; + level.iskillboosting = ::sd_iskillboosting; + level.endgameonscorelimit = 0; + game[ "dialog" ][ "gametype" ] = "sd_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "hcsd_start"; + game[ "dialog" ][ "offense_obj" ] = "destroy_start"; + game[ "dialog" ][ "defense_obj" ] = "defend_start"; + game[ "dialog" ][ "sudden_death" ] = "generic_boost"; + game[ "dialog" ][ "last_one" ] = "encourage_last"; + game[ "dialog" ][ "halftime" ] = "sd_halftime"; + if ( !sessionmodeissystemlink() && !sessionmodeisonlinegame() && issplitscreen() ) + { + setscoreboardcolumns( "score", "kills", "plants", "defuses", "deaths" ); + } + else + { + setscoreboardcolumns( "score", "kills", "deaths", "plants", "defuses" ); + } +} + +onprecachegametype() +{ + game[ "bomb_dropped_sound" ] = "mpl_flag_drop_plr"; + game[ "bomb_recovered_sound" ] = "mpl_flag_pickup_plr"; + precacheshader( "waypoint_bomb" ); + precacheshader( "hud_suitcase_bomb" ); + precacheshader( "waypoint_target" ); + precacheshader( "waypoint_target_a" ); + precacheshader( "waypoint_target_b" ); + precacheshader( "waypoint_defend" ); + precacheshader( "waypoint_defend_a" ); + precacheshader( "waypoint_defend_b" ); + precacheshader( "waypoint_defuse" ); + precacheshader( "waypoint_defuse_a" ); + precacheshader( "waypoint_defuse_b" ); + precacheshader( "compass_waypoint_target" ); + precacheshader( "compass_waypoint_target_a" ); + precacheshader( "compass_waypoint_target_b" ); + precacheshader( "compass_waypoint_defend" ); + precacheshader( "compass_waypoint_defend_a" ); + precacheshader( "compass_waypoint_defend_b" ); + precacheshader( "compass_waypoint_defuse" ); + precacheshader( "compass_waypoint_defuse_a" ); + precacheshader( "compass_waypoint_defuse_b" ); + precachestring( &"MP_EXPLOSIVES_BLOWUP_BY" ); + precachestring( &"MP_EXPLOSIVES_RECOVERED_BY" ); + precachestring( &"MP_EXPLOSIVES_DROPPED_BY" ); + precachestring( &"MP_EXPLOSIVES_PLANTED_BY" ); + precachestring( &"MP_EXPLOSIVES_DEFUSED_BY" ); + precachestring( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" ); + precachestring( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" ); + precachestring( &"MP_CANT_PLANT_WITHOUT_BOMB" ); + precachestring( &"MP_PLANTING_EXPLOSIVE" ); + precachestring( &"MP_DEFUSING_EXPLOSIVE" ); +} + +sd_getteamkillpenalty( einflictor, attacker, smeansofdeath, sweapon ) +{ + teamkill_penalty = maps/mp/gametypes/_globallogic_defaults::default_getteamkillpenalty( einflictor, attacker, smeansofdeath, sweapon ); + if ( isDefined( self.isdefusing ) || self.isdefusing && isDefined( self.isplanting ) && self.isplanting ) + { + teamkill_penalty *= level.teamkillpenaltymultiplier; + } + return teamkill_penalty; +} + +sd_getteamkillscore( einflictor, attacker, smeansofdeath, sweapon ) +{ + teamkill_score = maps/mp/gametypes/_rank::getscoreinfovalue( "team_kill" ); + if ( isDefined( self.isdefusing ) || self.isdefusing && isDefined( self.isplanting ) && self.isplanting ) + { + teamkill_score *= level.teamkillscoremultiplier; + } + return int( teamkill_score ); +} + +onroundswitch() +{ + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + if ( game[ "teamScores" ][ "allies" ] == ( level.scorelimit - 1 ) && game[ "teamScores" ][ "axis" ] == ( level.scorelimit - 1 ) ) + { + aheadteam = getbetterteam(); + if ( aheadteam != game[ "defenders" ] ) + { + game[ "switchedsides" ] = !game[ "switchedsides" ]; + } + level.halftimetype = "overtime"; + } + else + { + level.halftimetype = "halftime"; + game[ "switchedsides" ] = !game[ "switchedsides" ]; + } +} + +getbetterteam() +{ + kills[ "allies" ] = 0; + kills[ "axis" ] = 0; + deaths[ "allies" ] = 0; + deaths[ "axis" ] = 0; + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + team = player.pers[ "team" ]; + if ( isDefined( team ) || team == "allies" && team == "axis" ) + { + kills[ team ] += player.kills; + deaths[ team ] += player.deaths; + } + i++; + } + if ( kills[ "allies" ] > kills[ "axis" ] ) + { + return "allies"; + } + else + { + if ( kills[ "axis" ] > kills[ "allies" ] ) + { + return "axis"; + } + } + if ( deaths[ "allies" ] < deaths[ "axis" ] ) + { + return "allies"; + } + else + { + if ( deaths[ "axis" ] < deaths[ "allies" ] ) + { + return "axis"; + } + } + if ( randomint( 2 ) == 0 ) + { + return "allies"; + } + return "axis"; +} + +onstartgametype() +{ + setbombtimer( "A", 0 ); + setmatchflag( "bomb_timer_a", 0 ); + setbombtimer( "B", 0 ); + setmatchflag( "bomb_timer_b", 0 ); + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + if ( game[ "switchedsides" ] ) + { + oldattackers = game[ "attackers" ]; + olddefenders = game[ "defenders" ]; + game[ "attackers" ] = olddefenders; + game[ "defenders" ] = oldattackers; + } + setclientnamemode( "manual_change" ); + game[ "strings" ][ "target_destroyed" ] = &"MP_TARGET_DESTROYED"; + game[ "strings" ][ "bomb_defused" ] = &"MP_BOMB_DEFUSED"; + precachestring( game[ "strings" ][ "target_destroyed" ] ); + precachestring( game[ "strings" ][ "bomb_defused" ] ); + level._effect[ "bombexplosion" ] = loadfx( "maps/mp_maps/fx_mp_exp_bomb" ); + setobjectivetext( game[ "attackers" ], &"OBJECTIVES_SD_ATTACKER" ); + setobjectivetext( game[ "defenders" ], &"OBJECTIVES_SD_DEFENDER" ); + if ( level.splitscreen ) + { + setobjectivescoretext( game[ "attackers" ], &"OBJECTIVES_SD_ATTACKER" ); + setobjectivescoretext( game[ "defenders" ], &"OBJECTIVES_SD_DEFENDER" ); + } + else + { + setobjectivescoretext( game[ "attackers" ], &"OBJECTIVES_SD_ATTACKER_SCORE" ); + setobjectivescoretext( game[ "defenders" ], &"OBJECTIVES_SD_DEFENDER_SCORE" ); + } + setobjectivehinttext( game[ "attackers" ], &"OBJECTIVES_SD_ATTACKER_HINT" ); + setobjectivehinttext( game[ "defenders" ], &"OBJECTIVES_SD_DEFENDER_HINT" ); + allowed[ 0 ] = "sd"; + allowed[ 1 ] = "bombzone"; + allowed[ 2 ] = "blocker"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 1 ); + level.spawnmaxs = ( 0, 0, 1 ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_sd_spawn_attacker" ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( "mp_sd_spawn_defender" ); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.spawn_start = []; + level.spawn_start[ "axis" ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_sd_spawn_defender" ); + level.spawn_start[ "allies" ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_sd_spawn_attacker" ); + thread updategametypedvars(); + thread bombs(); +} + +onspawnplayerunified() +{ + self.isplanting = 0; + self.isdefusing = 0; + self.isbombcarrier = 0; + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn ) +{ + if ( !predictedspawn ) + { + self.isplanting = 0; + self.isdefusing = 0; + self.isbombcarrier = 0; + } + if ( self.pers[ "team" ] == game[ "attackers" ] ) + { + spawnpointname = "mp_sd_spawn_attacker"; + } + else + { + spawnpointname = "mp_sd_spawn_defender"; + } + spawnpoints = maps/mp/gametypes/_spawnlogic::getspawnpointarray( spawnpointname ); +/# + assert( spawnpoints.size ); +#/ + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_random( spawnpoints ); + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "sd" ); + } +} + +sd_playerspawnedcb() +{ + level notify( "spawned_player" ); +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + thread checkallowspectating(); + if ( isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + maps/mp/_scoreevents::processscoreevent( "kill_sd", attacker, self, sweapon ); + } + inbombzone = 0; + index = 0; + while ( index < level.bombzones.size ) + { + dist = distance2d( self.origin, level.bombzones[ index ].curorigin ); + if ( dist < level.defaultoffenseradius ) + { + inbombzone = 1; + } + index++; + } + if ( inbombzone && isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] ) + { + if ( game[ "defenders" ] == self.pers[ "team" ] ) + { + attacker maps/mp/_medals::offenseglobalcount(); + attacker addplayerstatwithgametype( "OFFENDS", 1 ); + self recordkillmodifier( "defending" ); + maps/mp/_scoreevents::processscoreevent( "killed_defender", attacker, self, sweapon ); + } + else + { + if ( isDefined( attacker.pers[ "defends" ] ) ) + { + attacker.pers[ "defends" ]++; + attacker.defends = attacker.pers[ "defends" ]; + } + attacker maps/mp/_medals::defenseglobalcount(); + attacker addplayerstatwithgametype( "DEFENDS", 1 ); + self recordkillmodifier( "assaulting" ); + maps/mp/_scoreevents::processscoreevent( "killed_attacker", attacker, self, sweapon ); + } + } + if ( isplayer( attacker ) && attacker.pers[ "team" ] != self.pers[ "team" ] && isDefined( self.isbombcarrier ) && self.isbombcarrier == 1 ) + { + self recordkillmodifier( "carrying" ); + } + if ( self.isplanting == 1 ) + { + self recordkillmodifier( "planting" ); + } + if ( self.isdefusing == 1 ) + { + self recordkillmodifier( "defusing" ); + } +} + +checkallowspectating() +{ + self endon( "disconnect" ); + wait 0,05; + update = 0; + if ( level.numliveslivesleft = self.pers[ "lives" ]; + && !level.alivecount[ game[ "attackers" ] ] && !livesleft ) + { + level.spectateoverride[ game[ "attackers" ] ].allowenemyspectate = 1; + update = 1; + } + if ( !level.alivecount[ game[ "defenders" ] ] && !livesleft ) + { + level.spectateoverride[ game[ "defenders" ] ].allowenemyspectate = 1; + update = 1; + } + if ( update ) + { + maps/mp/gametypes/_spectating::updatespectatesettings(); + } +} + +sd_endgame( winningteam, endreasontext ) +{ + if ( isDefined( winningteam ) ) + { + maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective_delaypostprocessing( winningteam, 1 ); + } + thread maps/mp/gametypes/_globallogic::endgame( winningteam, endreasontext ); +} + +sd_endgamewithkillcam( winningteam, endreasontext ) +{ + sd_endgame( winningteam, endreasontext ); +} + +ondeadevent( team ) +{ + if ( level.bombexploded || level.bombdefused ) + { + return; + } + if ( team == "all" ) + { + if ( level.bombplanted ) + { + sd_endgamewithkillcam( game[ "attackers" ], game[ "strings" ][ game[ "defenders" ] + "_eliminated" ] ); + } + else + { + sd_endgamewithkillcam( game[ "defenders" ], game[ "strings" ][ game[ "attackers" ] + "_eliminated" ] ); + } + } + else if ( team == game[ "attackers" ] ) + { + if ( level.bombplanted ) + { + return; + } + sd_endgamewithkillcam( game[ "defenders" ], game[ "strings" ][ game[ "attackers" ] + "_eliminated" ] ); + } + else + { + if ( team == game[ "defenders" ] ) + { + sd_endgamewithkillcam( game[ "attackers" ], game[ "strings" ][ game[ "defenders" ] + "_eliminated" ] ); + } + } +} + +ononeleftevent( team ) +{ + if ( level.bombexploded || level.bombdefused ) + { + return; + } + warnlastplayer( team ); +} + +ontimelimit() +{ + if ( level.teambased ) + { + sd_endgame( game[ "defenders" ], game[ "strings" ][ "time_limit_reached" ] ); + } + else + { + sd_endgame( undefined, game[ "strings" ][ "time_limit_reached" ] ); + } +} + +warnlastplayer( team ) +{ + if ( !isDefined( level.warnedlastplayer ) ) + { + level.warnedlastplayer = []; + } + if ( isDefined( level.warnedlastplayer[ team ] ) ) + { + return; + } + level.warnedlastplayer[ team ] = 1; + players = level.players; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == team && isDefined( player.pers[ "class" ] ) ) + { + if ( player.sessionstate == "playing" && !player.afk ) + { + break; + } + } + else + { + i++; + } + } + if ( i == players.size ) + { + return; + } + players[ i ] thread givelastattackerwarning( team ); +} + +givelastattackerwarning( team ) +{ + self endon( "death" ); + self endon( "disconnect" ); + fullhealthtime = 0; + interval = 0,05; + self.lastmansd = 1; + enemyteam = game[ "defenders" ]; + if ( team == enemyteam ) + { + enemyteam = game[ "attackers" ]; + } + if ( level.alivecount[ enemyteam ] > 2 ) + { + self.lastmansddefeat3enemies = 1; + } + while ( 1 ) + { + if ( self.health != self.maxhealth ) + { + fullhealthtime = 0; + } + else + { + fullhealthtime += interval; + } + wait interval; + if ( self.health == self.maxhealth && fullhealthtime >= 3 ) + { + break; + } + else + { + } + } + self maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "last_one" ); + self playlocalsound( "mus_last_stand" ); +} + +updategametypedvars() +{ + level.planttime = getgametypesetting( "plantTime" ); + level.defusetime = getgametypesetting( "defuseTime" ); + level.bombtimer = getgametypesetting( "bombTimer" ); + level.multibomb = getgametypesetting( "multiBomb" ); + level.teamkillpenaltymultiplier = getgametypesetting( "teamKillPenalty" ); + level.teamkillscoremultiplier = getgametypesetting( "teamKillScore" ); + level.playerkillsmax = getgametypesetting( "playerKillsMax" ); + level.totalkillsmax = getgametypesetting( "totalKillsMax" ); +} + +bombs() +{ + level.bombplanted = 0; + level.bombdefused = 0; + level.bombexploded = 0; + trigger = getent( "sd_bomb_pickup_trig", "targetname" ); + if ( !isDefined( trigger ) ) + { +/# + maps/mp/_utility::error( "No sd_bomb_pickup_trig trigger found in map." ); +#/ + return; + } + visuals[ 0 ] = getent( "sd_bomb", "targetname" ); + if ( !isDefined( visuals[ 0 ] ) ) + { +/# + maps/mp/_utility::error( "No sd_bomb script_model found in map." ); +#/ + return; + } + precachemodel( "prop_suitcase_bomb" ); + precachestring( &"bomb" ); + if ( !level.multibomb ) + { + level.sdbomb = maps/mp/gametypes/_gameobjects::createcarryobject( game[ "attackers" ], trigger, visuals, vectorScale( ( 0, 0, 1 ), 32 ), &"bomb" ); + level.sdbomb maps/mp/gametypes/_gameobjects::allowcarry( "friendly" ); + level.sdbomb maps/mp/gametypes/_gameobjects::set2dicon( "friendly", "compass_waypoint_bomb" ); + level.sdbomb maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_bomb" ); + level.sdbomb maps/mp/gametypes/_gameobjects::setvisibleteam( "friendly" ); + level.sdbomb maps/mp/gametypes/_gameobjects::setcarryicon( "hud_suitcase_bomb" ); + level.sdbomb.allowweapons = 1; + level.sdbomb.onpickup = ::onpickup; + level.sdbomb.ondrop = ::ondrop; + } + else + { + trigger delete(); + visuals[ 0 ] delete(); + } + level.bombzones = []; + bombzones = getentarray( "bombzone", "targetname" ); + index = 0; + while ( index < bombzones.size ) + { + trigger = bombzones[ index ]; + visuals = getentarray( bombzones[ index ].target, "targetname" ); + name = istring( trigger.script_label ); + precachestring( name ); + precachestring( istring( "defuse" + trigger.script_label ) ); + bombzone = maps/mp/gametypes/_gameobjects::createuseobject( game[ "defenders" ], trigger, visuals, ( 0, 0, 1 ), name ); + bombzone maps/mp/gametypes/_gameobjects::allowuse( "enemy" ); + bombzone maps/mp/gametypes/_gameobjects::setusetime( level.planttime ); + bombzone maps/mp/gametypes/_gameobjects::setusetext( &"MP_PLANTING_EXPLOSIVE" ); + bombzone maps/mp/gametypes/_gameobjects::setusehinttext( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" ); + if ( !level.multibomb ) + { + bombzone maps/mp/gametypes/_gameobjects::setkeyobject( level.sdbomb ); + } + label = bombzone maps/mp/gametypes/_gameobjects::getlabel(); + bombzone.label = label; + bombzone maps/mp/gametypes/_gameobjects::set2dicon( "friendly", "compass_waypoint_defend" + label ); + bombzone maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_defend" + label ); + bombzone maps/mp/gametypes/_gameobjects::set2dicon( "enemy", "compass_waypoint_target" + label ); + bombzone maps/mp/gametypes/_gameobjects::set3dicon( "enemy", "waypoint_target" + label ); + bombzone maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + bombzone.onbeginuse = ::onbeginuse; + bombzone.onenduse = ::onenduse; + bombzone.onuse = ::onuseplantobject; + bombzone.oncantuse = ::oncantuse; + bombzone.useweapon = "briefcase_bomb_mp"; + bombzone.visuals[ 0 ].killcament = spawn( "script_model", bombzone.visuals[ 0 ].origin + vectorScale( ( 0, 0, 1 ), 128 ) ); + if ( !level.multibomb ) + { + bombzone.trigger setinvisibletoall(); + } + i = 0; + while ( i < visuals.size ) + { + if ( isDefined( visuals[ i ].script_exploder ) ) + { + bombzone.exploderindex = visuals[ i ].script_exploder; + break; + } + else + { + i++; + } + } + level.bombzones[ level.bombzones.size ] = bombzone; + bombzone.bombdefusetrig = getent( visuals[ 0 ].target, "targetname" ); +/# + assert( isDefined( bombzone.bombdefusetrig ) ); +#/ + bombzone.bombdefusetrig.origin += vectorScale( ( 0, 0, 1 ), 10000 ); + bombzone.bombdefusetrig.label = label; + index++; + } + index = 0; + while ( index < level.bombzones.size ) + { + array = []; + otherindex = 0; + while ( otherindex < level.bombzones.size ) + { + if ( otherindex != index ) + { + array[ array.size ] = level.bombzones[ otherindex ]; + } + otherindex++; + } + level.bombzones[ index ].otherbombzones = array; + index++; + } +} + +onbeginuse( player ) +{ + if ( self maps/mp/gametypes/_gameobjects::isfriendlyteam( player.pers[ "team" ] ) ) + { + player playsound( "mpl_sd_bomb_defuse" ); + player.isdefusing = 1; + player thread maps/mp/gametypes/_battlechatter_mp::gametypespecificbattlechatter( "sd_enemyplant", player.pers[ "team" ] ); + if ( isDefined( level.sdbombmodel ) ) + { + level.sdbombmodel hide(); + } + } + else + { + player.isplanting = 1; + player thread maps/mp/gametypes/_battlechatter_mp::gametypespecificbattlechatter( "sd_friendlyplant", player.pers[ "team" ] ); + while ( level.multibomb ) + { + i = 0; + while ( i < self.otherbombzones.size ) + { + self.otherbombzones[ i ] maps/mp/gametypes/_gameobjects::disableobject(); + i++; + } + } + } + player playsound( "fly_bomb_raise_plr" ); +} + +onenduse( team, player, result ) +{ + if ( !isDefined( player ) ) + { + return; + } + player.isdefusing = 0; + player.isplanting = 0; + player notify( "event_ended" ); + if ( self maps/mp/gametypes/_gameobjects::isfriendlyteam( player.pers[ "team" ] ) ) + { + if ( isDefined( level.sdbombmodel ) && !result ) + { + level.sdbombmodel show(); + } + } + else + { + while ( level.multibomb && !result ) + { + i = 0; + while ( i < self.otherbombzones.size ) + { + self.otherbombzones[ i ] maps/mp/gametypes/_gameobjects::enableobject(); + i++; + } + } + } +} + +oncantuse( player ) +{ + player iprintlnbold( &"MP_CANT_PLANT_WITHOUT_BOMB" ); +} + +onuseplantobject( player ) +{ + if ( !self maps/mp/gametypes/_gameobjects::isfriendlyteam( player.pers[ "team" ] ) ) + { + self maps/mp/gametypes/_gameobjects::setflags( 1 ); + level thread bombplanted( self, player ); + player logstring( "bomb planted: " + self.label ); + index = 0; + while ( index < level.bombzones.size ) + { + if ( level.bombzones[ index ] == self ) + { + index++; + continue; + } + else + { + level.bombzones[ index ] maps/mp/gametypes/_gameobjects::disableobject(); + } + index++; + } + thread playsoundonplayers( "mus_sd_planted" + "_" + level.teampostfix[ player.pers[ "team" ] ] ); + player notify( "bomb_planted" ); + level thread maps/mp/_popups::displayteammessagetoall( &"MP_EXPLOSIVES_PLANTED_BY", player ); + if ( isDefined( player.pers[ "plants" ] ) ) + { + player.pers[ "plants" ]++; + player.plants = player.pers[ "plants" ]; + } + maps/mp/_demo::bookmark( "event", getTime(), player ); + player addplayerstatwithgametype( "PLANTS", 1 ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "bomb_planted" ); + maps/mp/_scoreevents::processscoreevent( "planted_bomb", player ); + player recordgameevent( "plant" ); + } +} + +onusedefuseobject( player ) +{ + self maps/mp/gametypes/_gameobjects::setflags( 0 ); + player notify( "bomb_defused" ); + player logstring( "bomb defused: " + self.label ); + bbprint( "mpobjective", "gametime %d objtype %s label %s team %s", getTime(), "sd_bombdefuse", self.label, player.pers[ "team" ] ); + level thread bombdefused(); + self maps/mp/gametypes/_gameobjects::disableobject(); + level thread maps/mp/_popups::displayteammessagetoall( &"MP_EXPLOSIVES_DEFUSED_BY", player ); + if ( isDefined( player.pers[ "defuses" ] ) ) + { + player.pers[ "defuses" ]++; + player.defuses = player.pers[ "defuses" ]; + } + player addplayerstatwithgametype( "DEFUSES", 1 ); + maps/mp/_demo::bookmark( "event", getTime(), player ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "bomb_defused" ); + if ( isDefined( player.lastmansd ) && player.lastmansd == 1 ) + { + maps/mp/_scoreevents::processscoreevent( "defused_bomb_last_man_alive", player ); + } + else + { + maps/mp/_scoreevents::processscoreevent( "defused_bomb", player ); + } + player recordgameevent( "defuse" ); +} + +ondrop( player ) +{ + if ( !level.bombplanted ) + { + maps/mp/gametypes/_globallogic_audio::leaderdialog( "bomb_lost", game[ "attackers" ] ); + if ( isDefined( player ) ) + { + player logstring( "bomb dropped" ); + } + else + { + logstring( "bomb dropped" ); + } + } + player notify( "event_ended" ); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_bomb" ); + maps/mp/_utility::playsoundonplayers( game[ "bomb_dropped_sound" ], game[ "attackers" ] ); +} + +onpickup( player ) +{ + player.isbombcarrier = 1; + player recordgameevent( "pickup" ); + self maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_defend" ); + if ( !level.bombdefused ) + { + if ( isDefined( player ) && isDefined( player.name ) ) + { + player addplayerstatwithgametype( "PICKUPS", 1 ); + } + team = self maps/mp/gametypes/_gameobjects::getownerteam(); + otherteam = getotherteam( team ); + maps/mp/gametypes/_globallogic_audio::leaderdialog( "bomb_acquired", game[ "attackers" ] ); + player logstring( "bomb taken" ); + } + maps/mp/_utility::playsoundonplayers( game[ "bomb_recovered_sound" ], game[ "attackers" ] ); + i = 0; + while ( i < level.bombzones.size ) + { + level.bombzones[ i ].trigger setinvisibletoall(); + level.bombzones[ i ].trigger setvisibletoplayer( player ); + i++; + } +} + +onreset() +{ +} + +bombplantedmusicdelay() +{ + level endon( "bomb_defused" ); + time = level.bombtimer - 30; +/# + if ( getDvarInt( #"0BC4784C" ) > 0 ) + { + println( "Music System - waiting to set TIME_OUT: " + time ); +#/ + } + if ( time > 1 ) + { + wait time; + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "TIME_OUT", "both" ); + } +} + +bombplanted( destroyedobj, player ) +{ + maps/mp/gametypes/_globallogic_utils::pausetimer(); + level.bombplanted = 1; + team = player.pers[ "team" ]; + destroyedobj.visuals[ 0 ] thread maps/mp/gametypes/_globallogic_utils::playtickingsound( "mpl_sab_ui_suitcasebomb_timer" ); + level thread bombplantedmusicdelay(); + level.tickingobject = destroyedobj.visuals[ 0 ]; + level.timelimitoverride = 1; + setgameendtime( int( getTime() + ( level.bombtimer * 1000 ) ) ); + label = destroyedobj maps/mp/gametypes/_gameobjects::getlabel(); + setmatchflag( "bomb_timer" + label, 1 ); + if ( label == "_a" ) + { + setbombtimer( "A", int( getTime() + ( level.bombtimer * 1000 ) ) ); + } + else + { + setbombtimer( "B", int( getTime() + ( level.bombtimer * 1000 ) ) ); + } + bbprint( "mpobjective", "gametime %d objtype %s label %s team %s", getTime(), "sd_bombplant", label, team ); + if ( !level.multibomb ) + { + level.sdbomb maps/mp/gametypes/_gameobjects::allowcarry( "none" ); + level.sdbomb maps/mp/gametypes/_gameobjects::setvisibleteam( "none" ); + level.sdbomb maps/mp/gametypes/_gameobjects::setdropped(); + level.sdbombmodel = level.sdbomb.visuals[ 0 ]; + } + else + { + index = 0; + while ( index < level.players.size ) + { + if ( isDefined( level.players[ index ].carryicon ) ) + { + level.players[ index ].carryicon destroyelem(); + } + index++; + } + trace = bullettrace( player.origin + vectorScale( ( 0, 0, 1 ), 20 ), player.origin - vectorScale( ( 0, 0, 1 ), 2000 ), 0, player ); + tempangle = randomfloat( 360 ); + forward = ( cos( tempangle ), sin( tempangle ), 0 ); + forward = vectornormalize( forward - vectorScale( trace[ "normal" ], vectordot( forward, trace[ "normal" ] ) ) ); + dropangles = vectorToAngle( forward ); + level.sdbombmodel = spawn( "script_model", trace[ "position" ] ); + level.sdbombmodel.angles = dropangles; + level.sdbombmodel setmodel( "prop_suitcase_bomb" ); + } + destroyedobj maps/mp/gametypes/_gameobjects::allowuse( "none" ); + destroyedobj maps/mp/gametypes/_gameobjects::setvisibleteam( "none" ); + label = destroyedobj maps/mp/gametypes/_gameobjects::getlabel(); + trigger = destroyedobj.bombdefusetrig; + trigger.origin = level.sdbombmodel.origin; + visuals = []; + defuseobject = maps/mp/gametypes/_gameobjects::createuseobject( game[ "defenders" ], trigger, visuals, vectorScale( ( 0, 0, 1 ), 32 ), istring( "defuse" + label ) ); + defuseobject maps/mp/gametypes/_gameobjects::allowuse( "friendly" ); + defuseobject maps/mp/gametypes/_gameobjects::setusetime( level.defusetime ); + defuseobject maps/mp/gametypes/_gameobjects::setusetext( &"MP_DEFUSING_EXPLOSIVE" ); + defuseobject maps/mp/gametypes/_gameobjects::setusehinttext( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" ); + defuseobject maps/mp/gametypes/_gameobjects::setvisibleteam( "any" ); + defuseobject maps/mp/gametypes/_gameobjects::set2dicon( "friendly", "compass_waypoint_defuse" + label ); + defuseobject maps/mp/gametypes/_gameobjects::set2dicon( "enemy", "compass_waypoint_defend" + label ); + defuseobject maps/mp/gametypes/_gameobjects::set3dicon( "friendly", "waypoint_defuse" + label ); + defuseobject maps/mp/gametypes/_gameobjects::set3dicon( "enemy", "waypoint_defend" + label ); + defuseobject maps/mp/gametypes/_gameobjects::setflags( 1 ); + defuseobject.label = label; + defuseobject.onbeginuse = ::onbeginuse; + defuseobject.onenduse = ::onenduse; + defuseobject.onuse = ::onusedefuseobject; + defuseobject.useweapon = "briefcase_bomb_defuse_mp"; + player.isbombcarrier = 0; + bombtimerwait(); + setbombtimer( "A", 0 ); + setbombtimer( "B", 0 ); + setmatchflag( "bomb_timer_a", 0 ); + setmatchflag( "bomb_timer_b", 0 ); + destroyedobj.visuals[ 0 ] maps/mp/gametypes/_globallogic_utils::stoptickingsound(); + if ( level.gameended || level.bombdefused ) + { + return; + } + level.bombexploded = 1; + bbprint( "mpobjective", "gametime %d objtype %s label %s team %s", getTime(), "sd_bombexplode", label, team ); + explosionorigin = level.sdbombmodel.origin + vectorScale( ( 0, 0, 1 ), 12 ); + level.sdbombmodel hide(); + if ( isDefined( player ) ) + { + destroyedobj.visuals[ 0 ] radiusdamage( explosionorigin, 512, 200, 20, player, "MOD_EXPLOSIVE", "briefcase_bomb_mp" ); + level thread maps/mp/_popups::displayteammessagetoall( &"MP_EXPLOSIVES_BLOWUP_BY", player ); + maps/mp/_scoreevents::processscoreevent( "bomb_detonated", player ); + player addplayerstatwithgametype( "DESTRUCTIONS", 1 ); + player recordgameevent( "destroy" ); + } + else + { + destroyedobj.visuals[ 0 ] radiusdamage( explosionorigin, 512, 200, 20, undefined, "MOD_EXPLOSIVE", "briefcase_bomb_mp" ); + } + rot = randomfloat( 360 ); + explosioneffect = spawnfx( level._effect[ "bombexplosion" ], explosionorigin + vectorScale( ( 0, 0, 1 ), 50 ), ( 0, 0, 1 ), ( cos( rot ), sin( rot ), 0 ) ); + triggerfx( explosioneffect ); + thread playsoundinspace( "mpl_sd_exp_suitcase_bomb_main", explosionorigin ); + if ( isDefined( destroyedobj.exploderindex ) ) + { + exploder( destroyedobj.exploderindex ); + } + index = 0; + while ( index < level.bombzones.size ) + { + level.bombzones[ index ] maps/mp/gametypes/_gameobjects::disableobject(); + index++; + } + defuseobject maps/mp/gametypes/_gameobjects::disableobject(); + setgameendtime( 0 ); + wait 3; + sd_endgame( game[ "attackers" ], game[ "strings" ][ "target_destroyed" ] ); +} + +bombtimerwait() +{ + level endon( "game_ended" ); + level endon( "bomb_defused" ); + maps/mp/gametypes/_hostmigration::waitlongdurationwithgameendtimeupdate( level.bombtimer ); +} + +bombdefused() +{ + level.tickingobject maps/mp/gametypes/_globallogic_utils::stoptickingsound(); + level.bombdefused = 1; + setbombtimer( "A", 0 ); + setbombtimer( "B", 0 ); + setmatchflag( "bomb_timer_a", 0 ); + setmatchflag( "bomb_timer_b", 0 ); + level notify( "bomb_defused" ); + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "SILENT", "both" ); + wait 1,5; + setgameendtime( 0 ); + sd_endgame( game[ "defenders" ], game[ "strings" ][ "bomb_defused" ] ); +} + +sd_iskillboosting() +{ + roundsplayed = maps/mp/_utility::getroundsplayed(); + if ( level.playerkillsmax == 0 ) + { + return 0; + } + if ( game[ "totalKills" ] > ( level.totalkillsmax * ( roundsplayed + 1 ) ) ) + { + return 1; + } + if ( self.kills > ( level.playerkillsmax * ( roundsplayed + 1 ) ) ) + { + return 1; + } + if ( level.teambased || self.team == "allies" && self.team == "axis" ) + { + if ( game[ "totalKillsTeam" ][ self.team ] > ( level.playerkillsmax * ( roundsplayed + 1 ) ) ) + { + return 1; + } + } + return 0; +} diff --git a/patch_mp/maps/mp/gametypes/shrp.gsc b/patch_mp/maps/mp/gametypes/shrp.gsc new file mode 100644 index 0000000..5c7020c --- /dev/null +++ b/patch_mp/maps/mp/gametypes/shrp.gsc @@ -0,0 +1,716 @@ +#include maps/mp/gametypes/_persistence; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/_scoreevents; +#include maps/mp/gametypes/_hostmigration; +#include maps/mp/gametypes/_wager; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + level.pointsperweaponkill = getgametypesetting( "pointsPerWeaponKill" ); + level.pointspermeleekill = getgametypesetting( "pointsPerMeleeKill" ); + level.shrpweapontimer = getgametypesetting( "weaponTimer" ); + level.shrpweaponnumber = getgametypesetting( "weaponCount" ); + registertimelimit( ( level.shrpweaponnumber * level.shrpweapontimer ) / 60, ( level.shrpweaponnumber * level.shrpweapontimer ) / 60 ); + registerscorelimit( 0, 50000 ); + registerroundlimit( 0, 10 ); + registerroundwinlimit( 0, 10 ); + registernumlives( 0, 100 ); + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onplayerkilled = ::onplayerkilled; + level.onwagerawards = ::onwagerawards; + game[ "dialog" ][ "gametype" ] = "ss_start"; + level.givecustomloadout = ::givecustomloadout; + precachestring( &"MP_SHRP_WEAPONS_CYCLED" ); + precachestring( &"MP_SHRP_PENULTIMATE_RND" ); + precachestring( &"MP_SHRP_PENULTIMATE_MULTIPLIER" ); + precachestring( &"MP_SHRP_RND" ); + precachestring( &"MP_SHRP_FINAL_MULTIPLIER" ); + precachestring( &"MP_SHRP_COUNTDOWN" ); + precacheshader( "perk_times_two" ); + precacheitem( "minigun_wager_mp" ); + precacheitem( "m32_wager_mp" ); + game[ "dialog" ][ "wm_weapons_cycled" ] = "ssharp_cycle_01"; + game[ "dialog" ][ "wm_final_weapon" ] = "ssharp_fweapon"; + game[ "dialog" ][ "wm_bonus_rnd" ] = "ssharp_2multi_00"; + game[ "dialog" ][ "wm_shrp_rnd" ] = "ssharp_sround"; + game[ "dialog" ][ "wm_bonus0" ] = "boost_gen_05"; + game[ "dialog" ][ "wm_bonus1" ] = "boost_gen_05"; + game[ "dialog" ][ "wm_bonus2" ] = "boost_gen_05"; + game[ "dialog" ][ "wm_bonus3" ] = "boost_gen_05"; + game[ "dialog" ][ "wm_bonus4" ] = "boost_gen_05"; + game[ "dialog" ][ "wm_bonus5" ] = "boost_gen_05"; + setscoreboardcolumns( "pointstowin", "kills", "deaths", "stabs", "x2score" ); +} + +onstartgametype() +{ + setdvar( "scr_disable_weapondrop", 1 ); + setdvar( "scr_xpscale", 0 ); + setdvar( "ui_guncycle", 0 ); + makedvarserverinfo( "ui_guncycle", 0 ); + setclientnamemode( "auto_change" ); + setobjectivetext( "allies", &"OBJECTIVES_SHRP" ); + setobjectivetext( "axis", &"OBJECTIVES_SHRP" ); + attach_compatibility_init(); + if ( level.splitscreen ) + { + setobjectivescoretext( "allies", &"OBJECTIVES_SHRP" ); + setobjectivescoretext( "axis", &"OBJECTIVES_SHRP" ); + } + else + { + setobjectivescoretext( "allies", &"OBJECTIVES_SHRP_SCORE" ); + setobjectivescoretext( "axis", &"OBJECTIVES_SHRP_SCORE" ); + } + setobjectivehinttext( "allies", &"OBJECTIVES_SHRP_HINT" ); + setobjectivehinttext( "axis", &"OBJECTIVES_SHRP_HINT" ); + allowed[ 0 ] = "shrp"; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 0 ); + level.spawnmaxs = ( 0, 0, 0 ); + newspawns = getentarray( "mp_wager_spawn", "classname" ); + if ( newspawns.size > 0 ) + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_wager_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_wager_spawn" ); + } + else + { + maps/mp/gametypes/_spawnlogic::addspawnpoints( "allies", "mp_dm_spawn" ); + maps/mp/gametypes/_spawnlogic::addspawnpoints( "axis", "mp_dm_spawn" ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + level.usestartspawns = 0; + maps/mp/gametypes/_wager::addpowerup( "specialty_bulletflinch", "perk", &"PERKS_TOUGHNESS", "perk_warrior" ); + maps/mp/gametypes/_wager::addpowerup( "specialty_movefaster", "perk", &"PERKS_LIGHTWEIGHT", "perk_lightweight" ); + maps/mp/gametypes/_wager::addpowerup( "specialty_fallheight", "perk", &"PERKS_LIGHTWEIGHT", "perk_lightweight" ); + maps/mp/gametypes/_wager::addpowerup( "specialty_longersprint", "perk", &"PERKS_EXTREME_CONDITIONING", "perk_marathon" ); + maps/mp/gametypes/_wager::addpowerup( 2, "score_multiplier", &"PERKS_SCORE_MULTIPLIER", "perk_times_two" ); + level.guncycletimer = createservertimer( "extrasmall", 1,2 ); + level.guncycletimer.horzalign = "user_left"; + level.guncycletimer.vertalign = "user_top"; + level.guncycletimer.x = 10; + level.guncycletimer.y = 123; + level.guncycletimer.alignx = "left"; + level.guncycletimer.aligny = "top"; + level.guncycletimer.label = &"MP_SHRP_COUNTDOWN"; + level.guncycletimer.alpha = 0; + level.guncycletimer.hidewheninkillcam = 1; + level.displayroundendtext = 0; + level.quickmessagetoall = 1; + level thread chooserandomguns(); + level thread clearpowerupsongameend(); +} + +attach_compatibility_init() +{ + level.attach_compatible = []; + set_attachtable_id(); + i = 0; + while ( i < 33 ) + { + itemrow = tablelookuprownum( level.attachtableid, 9, i ); + if ( itemrow > -1 ) + { + name = tablelookupcolumnforrow( level.attachtableid, itemrow, 4 ); + level.attach_compatible[ name ] = []; + compatible = tablelookupcolumnforrow( level.attachtableid, itemrow, 11 ); + level.attach_compatible[ name ] = strtok( compatible, " " ); + } + i++; + } +} + +set_attachtable_id() +{ + if ( !isDefined( level.attachtableid ) ) + { + level.attachtableid = "mp/attachmentTable.csv"; + } +} + +addguntoprogression( gunname, altname ) +{ + if ( !isDefined( level.gunprogression ) ) + { + level.gunprogression = []; + } + newweapon = spawnstruct(); + newweapon.names = []; + newweapon.names[ newweapon.names.size ] = gunname; + if ( isDefined( altname ) ) + { + newweapon.names[ newweapon.names.size ] = altname; + } + level.gunprogression[ level.gunprogression.size ] = newweapon; +} + +getrandomgunfromprogression() +{ + weaponidkeys = getarraykeys( level.tbl_weaponids ); + numweaponidkeys = weaponidkeys.size; + gunprogressionsize = 0; + if ( isDefined( level.gunprogression ) ) + { + size = level.gunprogression.size; + } +/# + debug_weapon = getDvar( #"1C6DE858" ); +#/ + allowproneblock = 1; + players = get_players(); + _a256 = players; + _k256 = getFirstArrayKey( _a256 ); + while ( isDefined( _k256 ) ) + { + player = _a256[ _k256 ]; + if ( player getstance() == "prone" ) + { + allowproneblock = 0; + break; + } + else + { + _k256 = getNextArrayKey( _a256, _k256 ); + } + } + while ( 1 ) + { + randomindex = randomint( numweaponidkeys + gunprogressionsize ); + baseweaponname = ""; + weaponname = ""; + if ( randomindex < numweaponidkeys ) + { + id = random( level.tbl_weaponids ); + while ( id[ "group" ] != "weapon_launcher" && id[ "group" ] != "weapon_sniper" && id[ "group" ] != "weapon_lmg" && id[ "group" ] != "weapon_assault" && id[ "group" ] != "weapon_smg" && id[ "group" ] != "weapon_pistol" && id[ "group" ] != "weapon_cqb" && id[ "group" ] != "weapon_special" ) + { + continue; + } + while ( id[ "reference" ] == "weapon_null" ) + { + continue; + } + baseweaponname = id[ "reference" ]; + attachmentlist = id[ "attachment" ]; + if ( baseweaponname == "m32" ) + { + baseweaponname = "m32_wager"; + } + if ( baseweaponname == "minigun" ) + { + baseweaponname = "minigun_wager"; + } + while ( baseweaponname == "riotshield" ) + { + continue; + } + if ( getDvarInt( #"97A055DA" ) == 0 && baseweaponname == "peacekeeper" ) + { + continue; + } + weaponname = addrandomattachmenttoweaponname( baseweaponname, attachmentlist ); + if ( !allowproneblock && weaponblocksprone( weaponname ) ) + { + continue; + } + } + else baseweaponname = level.gunprogression[ randomindex - numweaponidkeys ].names[ 0 ]; + weaponname = level.gunprogression[ randomindex - numweaponidkeys ].names[ 0 ]; + if ( !isDefined( level.usedbaseweapons ) ) + { + level.usedbaseweapons = []; + level.usedbaseweapons[ 0 ] = "fhj18"; + } + skipweapon = 0; + i = 0; + while ( i < level.usedbaseweapons.size ) + { + if ( level.usedbaseweapons[ i ] == baseweaponname ) + { + skipweapon = 1; + break; + } + else + { + i++; + } + } + while ( skipweapon ) + { + continue; + } + level.usedbaseweapons[ level.usedbaseweapons.size ] = baseweaponname; +/# + if ( debug_weapon != "" ) + { + weaponname = debug_weapon; +#/ + } + return weaponname; + } +} + +addrandomattachmenttoweaponname( baseweaponname, attachmentlist ) +{ + if ( !isDefined( attachmentlist ) ) + { + return baseweaponname; + } + attachments = strtok( attachmentlist, " " ); + arrayremovevalue( attachments, "dw" ); + if ( attachments.size <= 0 ) + { + return baseweaponname + "_mp"; + } + attachments[ attachments.size ] = ""; + attachment = random( attachments ); + if ( attachment == "" ) + { + return baseweaponname + "_mp"; + } + if ( issubstr( attachment, "_" ) ) + { + attachment = strtok( attachment, "_" )[ 0 ]; + } + if ( isDefined( level.attach_compatible[ attachment ] ) && level.attach_compatible[ attachment ].size > 0 ) + { + attachment2 = level.attach_compatible[ attachment ][ randomint( level.attach_compatible[ attachment ].size ) ]; + contains = 0; + i = 0; + while ( i < attachments.size ) + { + if ( isDefined( attachment2 ) && attachments[ i ] == attachment2 ) + { + contains = 1; + break; + } + else + { + i++; + } + } + if ( contains ) + { + if ( attachment < attachment2 ) + { + return ( baseweaponname + "_mp+" ) + attachment + "+" + attachment2; + } + return ( baseweaponname + "_mp+" ) + attachment2 + "+" + attachment; + } + } + return ( baseweaponname + "_mp+" ) + attachment; +} + +waitlongdurationwithhostmigrationpause( nextguncycletime, duration ) +{ + endtime = getTime() + ( duration * 1000 ); + totaltimepassed = 0; + while ( getTime() < endtime ) + { + maps/mp/gametypes/_hostmigration::waittillhostmigrationstarts( ( endtime - getTime() ) / 1000 ); + if ( isDefined( level.hostmigrationtimer ) ) + { + setdvar( "ui_guncycle", 0 ); + timepassed = maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + totaltimepassed += timepassed; + endtime += timepassed; +/# + println( "[SHRP] timePassed = " + timepassed ); + println( "[SHRP] totatTimePassed = " + totaltimepassed ); + println( "[SHRP] level.discardTime = " + level.discardtime ); +#/ + setdvar( "ui_guncycle", nextguncycletime + totaltimepassed ); + } + } + maps/mp/gametypes/_hostmigration::waittillhostmigrationdone(); + return totaltimepassed; +} + +guncyclewaiter( nextguncycletime, waittime ) +{ + continuecycling = 1; + setdvar( "ui_guncycle", nextguncycletime ); + level.guncycletimer settimer( waittime ); + level.guncycletimer.alpha = 1; + timepassed = waitlongdurationwithhostmigrationpause( nextguncycletime, ( ( nextguncycletime - getTime() ) / 1000 ) - 6 ); + nextguncycletime += timepassed; + i = 6; + while ( i > 1 ) + { + j = 0; + while ( j < level.players.size ) + { + level.players[ j ] playlocalsound( "uin_timer_wager_beep" ); + j++; + } + timepassed = waitlongdurationwithhostmigrationpause( nextguncycletime, ( nextguncycletime - getTime() ) / 1000 / i ); + nextguncycletime += timepassed; + i--; + + } + i = 0; + while ( i < level.players.size ) + { + level.players[ i ] playlocalsound( "uin_timer_wager_last_beep" ); + i++; + } + if ( ( nextguncycletime - getTime() ) > 0 ) + { + wait ( ( nextguncycletime - getTime() ) / 1000 ); + } + level.shrprandomweapon = getrandomgunfromprogression(); + i = 0; + while ( i < level.players.size ) + { + level.players[ i ] notify( "remove_planted_weapons" ); + level.players[ i ] givecustomloadout( 0, 1 ); + i++; + } + return continuecycling; +} + +chooserandomguns() +{ + level endon( "game_ended" ); + level thread awardmostpointsmedalgameend(); + waittime = level.shrpweapontimer; + lightningwaittime = 15; + level.shrprandomweapon = getrandomgunfromprogression(); + if ( level.inprematchperiod ) + { + level waittill( "prematch_over" ); + } + guncycle = 1; + numguncycles = int( ( ( level.timelimit * 60 ) / waittime ) + 0,5 ); + while ( 1 ) + { + nextguncycletime = getTime() + ( waittime * 1000 ); + ispenultimateround = 0; + issharpshooterround = guncycle == ( numguncycles - 1 ); + i = 0; + while ( i < level.players.size ) + { + level.players[ i ].currentguncyclepoints = 0; + i++; + } + level.currentguncyclemaxpoints = 0; + guncyclewaiter( nextguncycletime, waittime ); + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + if ( ( guncycle + 1 ) == numguncycles ) + { + player maps/mp/gametypes/_wager::wagerannouncer( "wm_final_weapon" ); + } + else + { + player maps/mp/gametypes/_wager::wagerannouncer( "wm_weapons_cycled" ); + } + player checkawardmostpointsthiscycle(); + i++; + } + if ( ispenultimateround ) + { + level.sharpshootermultiplier = 2; + i = 0; + while ( i < level.players.size ) + { + level.players[ i ] thread maps/mp/gametypes/_wager::queuewagerpopup( &"MP_SHRP_PENULTIMATE_RND", 0, &"MP_SHRP_PENULTIMATE_MULTIPLIER", "wm_bonus_rnd" ); + i++; + } + } + else if ( issharpshooterround ) + { + lastmultiplier = level.sharpshootermultiplier; + if ( !isDefined( lastmultiplier ) ) + { + lastmultiplier = 1; + } + level.sharpshootermultiplier = 2; + setdvar( "ui_guncycle", 0 ); + level.guncycletimer.alpha = 0; + i = 0; + while ( i < level.players.size ) + { + level.players[ i ] thread maps/mp/gametypes/_wager::queuewagerpopup( &"MP_SHRP_RND", 0, &"MP_SHRP_FINAL_MULTIPLIER", "wm_shrp_rnd" ); + i++; + } + } + else level.sharpshootermultiplier = 1; + guncycle++; + } +} + +checkawardmostpointsthiscycle() +{ + if ( isDefined( self.currentguncyclepoints ) && self.currentguncyclepoints > 0 ) + { + if ( self.currentguncyclepoints == level.currentguncyclemaxpoints ) + { + maps/mp/_scoreevents::processscoreevent( "most_points_shrp", self ); + } + } +} + +awardmostpointsmedalgameend() +{ + level waittill( "game_end" ); + i = 0; + while ( i < level.players.size ) + { + level.players[ i ] checkawardmostpointsthiscycle(); + i++; + } +} + +givecustomloadout( takeallweapons, alreadyspawned ) +{ + chooserandombody = 0; + if ( !isDefined( alreadyspawned ) || !alreadyspawned ) + { + chooserandombody = 1; + } + self maps/mp/gametypes/_wager::setupblankrandomplayer( takeallweapons, chooserandombody, level.shrprandomweapon ); + self disableweaponcycling(); + self giveweapon( level.shrprandomweapon ); + self switchtoweapon( level.shrprandomweapon ); + self giveweapon( "knife_mp" ); + if ( !isDefined( alreadyspawned ) || !alreadyspawned ) + { + self setspawnweapon( level.shrprandomweapon ); + } + if ( isDefined( takeallweapons ) && !takeallweapons ) + { + self thread takeoldweapons(); + } + else + { + self enableweaponcycling(); + } + return level.shrprandomweapon; +} + +takeoldweapons() +{ + self endon( "disconnect" ); + self endon( "death" ); + for ( ;; ) + { + self waittill( "weapon_change", newweapon ); + if ( newweapon != "none" ) + { + break; + } + else + { + } + } + weaponslist = self getweaponslist(); + i = 0; + while ( i < weaponslist.size ) + { + if ( weaponslist[ i ] != level.shrprandomweapon && weaponslist[ i ] != "knife_mp" ) + { + self takeweapon( weaponslist[ i ] ); + } + i++; + } + self enableweaponcycling(); +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( isDefined( attacker ) && isplayer( attacker ) && attacker != self ) + { + if ( isDefined( level.sharpshootermultiplier ) && level.sharpshootermultiplier == 2 ) + { + if ( !isDefined( attacker.pers[ "x2kills" ] ) ) + { + attacker.pers[ "x2kills" ] = 1; + } + else + { + attacker.pers[ "x2kills" ]++; + } + attacker.x2kills = attacker.pers[ "x2kills" ]; + } + else + { + if ( isDefined( level.sharpshootermultiplier ) && level.sharpshootermultiplier == 3 ) + { + if ( !isDefined( attacker.pers[ "x3kills" ] ) ) + { + attacker.pers[ "x3kills" ] = 1; + } + else + { + attacker.pers[ "x3kills" ]++; + } + attacker.x2kills = attacker.pers[ "x3kills" ]; + } + } + if ( isDefined( self.scoremultiplier ) && self.scoremultiplier >= 2 ) + { + maps/mp/_scoreevents::processscoreevent( "kill_x2_score_shrp", attacker, self, sweapon ); + } + currentbonus = attacker.currentbonus; + if ( !isDefined( currentbonus ) ) + { + currentbonus = 0; + } + if ( currentbonus < level.poweruplist.size ) + { + attacker maps/mp/gametypes/_wager::givepowerup( level.poweruplist[ currentbonus ] ); + attacker thread maps/mp/gametypes/_wager::wagerannouncer( "wm_bonus" + currentbonus ); + if ( level.poweruplist[ currentbonus ].type == "score_multiplier" && attacker.scoremultiplier == 2 ) + { + maps/mp/_scoreevents::processscoreevent( "x2_score_shrp", attacker, self, sweapon ); + } + currentbonus++; + attacker.currentbonus = currentbonus; + } + if ( currentbonus >= level.poweruplist.size ) + { + if ( isDefined( attacker.powerups ) && isDefined( attacker.powerups.size ) && attacker.powerups.size > 0 ) + { + attacker thread maps/mp/gametypes/_wager::pulsepowerupicon( attacker.powerups.size - 1 ); + } + } + scoremultiplier = 1; + if ( isDefined( attacker.scoremultiplier ) ) + { + scoremultiplier = attacker.scoremultiplier; + } + if ( isDefined( level.sharpshootermultiplier ) ) + { + scoremultiplier *= level.sharpshootermultiplier; + } + scoreincrease = attacker.pointstowin; + i = 1; + while ( i <= scoremultiplier ) + { + if ( smeansofdeath == "MOD_MELEE" && level.shrprandomweapon != "knife_mp" && level.shrprandomweapon != "riotshield_mp" ) + { + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.pointspermeleekill ); + if ( i != 1 ) + { + maps/mp/_scoreevents::processscoreevent( "kill", attacker, self, sweapon ); + maps/mp/_scoreevents::processscoreevent( "wager_melee_kill", attacker, self, sweapon ); + } + i++; + continue; + } + else + { + attacker maps/mp/gametypes/_globallogic_score::givepointstowin( level.pointsperweaponkill ); + if ( !isDefined( attacker.currentguncyclepoints ) ) + { + attacker.currentguncyclepoints = 0; + } + attacker.currentguncyclepoints += level.pointsperweaponkill; + if ( level.currentguncyclemaxpoints < attacker.currentguncyclepoints ) + { + level.currentguncyclemaxpoints = attacker.currentguncyclepoints; + } + if ( i != 1 ) + { + maps/mp/_scoreevents::processscoreevent( "kill", attacker, self, sweapon ); + } + } + i++; + } + scoreincrease = attacker.pointstowin - scoreincrease; + if ( scoremultiplier > 1 || isDefined( level.sharpshootermultiplier ) && level.sharpshootermultiplier > 1 ) + { + attacker playlocalsound( "uin_alert_cash_register" ); + attacker.pers[ "x2score" ] += scoreincrease; + attacker.x2score = attacker.pers[ "x2score" ]; + } + } + self.currentbonus = 0; + self.scoremultiplier = 1; + self maps/mp/gametypes/_wager::clearpowerups(); +} + +onspawnplayerunified() +{ + maps/mp/gametypes/_spawning::onspawnplayer_unified(); + self thread infiniteammo(); +} + +onspawnplayer( predictedspawn ) +{ + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( self.pers[ "team" ] ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_dm( spawnpoints ); + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "shrp" ); + self thread infiniteammo(); + } +} + +infiniteammo() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + wait 0,1; + weapon = self getcurrentweapon(); + self givemaxammo( weapon ); + } +} + +onwagerawards() +{ + x2kills = self maps/mp/gametypes/_globallogic_score::getpersstat( "x2kills" ); + if ( !isDefined( x2kills ) ) + { + x2kills = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", x2kills, 0 ); + headshots = self maps/mp/gametypes/_globallogic_score::getpersstat( "headshots" ); + if ( !isDefined( headshots ) ) + { + headshots = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", headshots, 1 ); + bestkillstreak = self maps/mp/gametypes/_globallogic_score::getpersstat( "best_kill_streak" ); + if ( !isDefined( bestkillstreak ) ) + { + bestkillstreak = 0; + } + self maps/mp/gametypes/_persistence::setafteractionreportstat( "wagerAwards", bestkillstreak, 2 ); +} + +clearpowerupsongameend() +{ + level waittill( "game_ended" ); + i = 0; + while ( i < level.players.size ) + { + player = level.players[ i ]; + player maps/mp/gametypes/_wager::clearpowerups(); + i++; + } +} diff --git a/patch_mp/maps/mp/gametypes/tdm.gsc b/patch_mp/maps/mp/gametypes/tdm.gsc new file mode 100644 index 0000000..2176a6d --- /dev/null +++ b/patch_mp/maps/mp/gametypes/tdm.gsc @@ -0,0 +1,300 @@ +#include maps/mp/gametypes/_globallogic_audio; +#include maps/mp/gametypes/_globallogic_score; +#include maps/mp/gametypes/_spawnlogic; +#include maps/mp/gametypes/_spawning; +#include maps/mp/gametypes/_hud_util; +#include maps/mp/_utility; + +main() +{ + if ( getDvar( "mapname" ) == "mp_background" ) + { + return; + } + maps/mp/gametypes/_globallogic::init(); + maps/mp/gametypes/_callbacksetup::setupcallbacks(); + maps/mp/gametypes/_globallogic::setupcallbacks(); + registerroundswitch( 0, 9 ); + registertimelimit( 0, 1440 ); + registerscorelimit( 0, 50000 ); + registerroundlimit( 0, 10 ); + registerroundwinlimit( 0, 10 ); + registernumlives( 0, 100 ); + maps/mp/gametypes/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + level.scoreroundbased = getgametypesetting( "roundscorecarry" ) == 0; + level.teamscoreperkill = getgametypesetting( "teamScorePerKill" ); + level.teamscoreperdeath = getgametypesetting( "teamScorePerDeath" ); + level.teamscoreperheadshot = getgametypesetting( "teamScorePerHeadshot" ); + level.teambased = 1; + level.overrideteamscore = 1; + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::onspawnplayer; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onroundendgame = ::onroundendgame; + level.onroundswitch = ::onroundswitch; + level.onplayerkilled = ::onplayerkilled; + game[ "dialog" ][ "gametype" ] = "tdm_start"; + game[ "dialog" ][ "gametype_hardcore" ] = "hctdm_start"; + game[ "dialog" ][ "offense_obj" ] = "generic_boost"; + game[ "dialog" ][ "defense_obj" ] = "generic_boost"; + setscoreboardcolumns( "score", "kills", "deaths", "kdratio", "assists" ); +} + +onstartgametype() +{ + setclientnamemode( "auto_change" ); + if ( !isDefined( game[ "switchedsides" ] ) ) + { + game[ "switchedsides" ] = 0; + } + if ( game[ "switchedsides" ] ) + { + oldattackers = game[ "attackers" ]; + olddefenders = game[ "defenders" ]; + game[ "attackers" ] = olddefenders; + game[ "defenders" ] = oldattackers; + } + allowed[ 0 ] = "tdm"; + level.displayroundendtext = 0; + maps/mp/gametypes/_gameobjects::main( allowed ); + maps/mp/gametypes/_spawning::create_map_placed_influencers(); + level.spawnmins = ( 0, 0, 0 ); + level.spawnmaxs = ( 0, 0, 0 ); + _a135 = level.teams; + _k135 = getFirstArrayKey( _a135 ); + while ( isDefined( _k135 ) ) + { + team = _a135[ _k135 ]; + setobjectivetext( team, &"OBJECTIVES_TDM" ); + setobjectivehinttext( team, &"OBJECTIVES_TDM_HINT" ); + if ( level.splitscreen ) + { + setobjectivescoretext( team, &"OBJECTIVES_TDM" ); + } + else + { + setobjectivescoretext( team, &"OBJECTIVES_TDM_SCORE" ); + } + maps/mp/gametypes/_spawnlogic::addspawnpoints( team, "mp_tdm_spawn" ); + maps/mp/gametypes/_spawnlogic::placespawnpoints( maps/mp/gametypes/_spawning::gettdmstartspawnname( team ) ); + _k135 = getNextArrayKey( _a135, _k135 ); + } + maps/mp/gametypes/_spawning::updateallspawnpoints(); +/# + level.spawn_start = []; + _a161 = level.teams; + _k161 = getFirstArrayKey( _a161 ); + while ( isDefined( _k161 ) ) + { + team = _a161[ _k161 ]; + level.spawn_start[ team ] = maps/mp/gametypes/_spawnlogic::getspawnpointarray( maps/mp/gametypes/_spawning::gettdmstartspawnname( team ) ); + _k161 = getNextArrayKey( _a161, _k161 ); +#/ + } + level.mapcenter = maps/mp/gametypes/_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs ); + setmapcenter( level.mapcenter ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getrandomintermissionpoint(); + setdemointermissionpoint( spawnpoint.origin, spawnpoint.angles ); + if ( !isoneround() ) + { + level.displayroundendtext = 1; + if ( isscoreroundbased() ) + { + maps/mp/gametypes/_globallogic_score::resetteamscores(); + } + } +} + +onspawnplayerunified( question ) +{ + self.usingobj = undefined; + if ( level.usestartspawns && !level.ingraceperiod && !level.playerqueuedrespawn ) + { + level.usestartspawns = 0; + } + spawnteam = self.pers[ "team" ]; + if ( game[ "switchedsides" ] ) + { + spawnteam = getotherteam( spawnteam ); + } + if ( isDefined( question ) ) + { + question = 1; + } + if ( isDefined( question ) ) + { + question = -1; + } + if ( isDefined( spawnteam ) ) + { + spawnteam = spawnteam; + } + if ( !isDefined( spawnteam ) ) + { + spawnteam = -1; + } + maps/mp/gametypes/_spawning::onspawnplayer_unified(); +} + +onspawnplayer( predictedspawn, question ) +{ + pixbeginevent( "TDM:onSpawnPlayer" ); + self.usingobj = undefined; + if ( isDefined( question ) ) + { + question = 1; + } + if ( isDefined( question ) ) + { + question = -1; + } + spawnteam = self.pers[ "team" ]; + if ( isDefined( spawnteam ) ) + { + spawnteam = spawnteam; + } + if ( !isDefined( spawnteam ) ) + { + spawnteam = -1; + } + if ( level.ingraceperiod ) + { + spawnpoints = maps/mp/gametypes/_spawnlogic::getspawnpointarray( maps/mp/gametypes/_spawning::gettdmstartspawnname( spawnteam ) ); + if ( !spawnpoints.size ) + { + spawnpoints = maps/mp/gametypes/_spawnlogic::getspawnpointarray( maps/mp/gametypes/_spawning::getteamstartspawnname( spawnteam, "mp_sab_spawn" ) ); + } + if ( !spawnpoints.size ) + { + if ( game[ "switchedsides" ] ) + { + spawnteam = getotherteam( spawnteam ); + } + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( spawnteam ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( spawnpoints ); + } + else + { + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_random( spawnpoints ); + } + } + else + { + if ( game[ "switchedsides" ] ) + { + spawnteam = getotherteam( spawnteam ); + } + spawnpoints = maps/mp/gametypes/_spawnlogic::getteamspawnpoints( spawnteam ); + spawnpoint = maps/mp/gametypes/_spawnlogic::getspawnpoint_nearteam( spawnpoints ); + } + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "tdm" ); + } + pixendevent(); +} + +onendgame( winningteam ) +{ + if ( isDefined( winningteam ) && isDefined( level.teams[ winningteam ] ) ) + { + maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( winningteam, 1 ); + } +} + +onroundswitch() +{ + game[ "switchedsides" ] = !game[ "switchedsides" ]; + while ( level.roundscorecarry == 0 ) + { + _a288 = level.teams; + _k288 = getFirstArrayKey( _a288 ); + while ( isDefined( _k288 ) ) + { + team = _a288[ _k288 ]; + [[ level._setteamscore ]]( team, game[ "roundswon" ][ team ] ); + _k288 = getNextArrayKey( _a288, _k288 ); + } + } +} + +onroundendgame( roundwinner ) +{ + if ( level.roundscorecarry == 0 ) + { + _a299 = level.teams; + _k299 = getFirstArrayKey( _a299 ); + while ( isDefined( _k299 ) ) + { + team = _a299[ _k299 ]; + [[ level._setteamscore ]]( team, game[ "roundswon" ][ team ] ); + _k299 = getNextArrayKey( _a299, _k299 ); + } + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbygamestat( "roundswon" ); + } + else + { + winner = maps/mp/gametypes/_globallogic::determineteamwinnerbyteamscore(); + } + return winner; +} + +onscoreclosemusic() +{ + teamscores = []; + while ( !level.gameended ) + { + scorelimit = level.scorelimit; + scorethreshold = scorelimit * 0,1; + scorethresholdstart = abs( scorelimit - scorethreshold ); + scorelimitcheck = scorelimit - 10; + topscore = 0; + runnerupscore = 0; + _a327 = level.teams; + _k327 = getFirstArrayKey( _a327 ); + while ( isDefined( _k327 ) ) + { + team = _a327[ _k327 ]; + score = [[ level._getteamscore ]]( team ); + if ( score > topscore ) + { + runnerupscore = topscore; + topscore = score; + } + else + { + if ( score > runnerupscore ) + { + runnerupscore = score; + } + } + _k327 = getNextArrayKey( _a327, _k327 ); + } + scoredif = topscore - runnerupscore; + if ( scoredif <= scorethreshold && scorethresholdstart <= topscore ) + { + thread maps/mp/gametypes/_globallogic_audio::set_music_on_team( "TIME_OUT", "both" ); + thread maps/mp/gametypes/_globallogic_audio::actionmusicset(); + return; + } + wait 1; + } +} + +onplayerkilled( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime, deathanimduration ) +{ + if ( isplayer( attacker ) == 0 || attacker.team == self.team ) + { + return; + } + attacker maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( attacker.team, level.teamscoreperkill ); + self maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( self.team, level.teamscoreperdeath * -1 ); + if ( smeansofdeath == "MOD_HEAD_SHOT" ) + { + attacker maps/mp/gametypes/_globallogic_score::giveteamscoreforobjective( attacker.team, level.teamscoreperheadshot ); + } +} diff --git a/patch_mp/readme.md b/patch_mp/readme.md new file mode 100644 index 0000000..2277a73 --- /dev/null +++ b/patch_mp/readme.md @@ -0,0 +1,86 @@ +### The following gscs compile and run successfully with no known errors: +``` +patch_mp/maps/mp/gametypes/_clientids.gsc +patch_mp/maps/mp/gametypes/_globalentities.gsc +patch_mp/maps/mp/gametypes/_scoreboard.gsc +patch_mp/maps/mp/gametypes/_shellshock.gsc +``` +### The following scripts compile and run successfully with minor errors: +``` +``` +### The following scripts compile and run successfully with major errors: +``` +``` +### The following scripts compile and run serverside but clients cannot join due to exe_client_field_mismatch +``` +``` +### The following scripts compile but cause a minidump or other severe error: +``` +``` +### The following scripts have been checked, but they have not been tested yet +``` +``` +### The following scripts are not checked yet, uploaded to setup a baseline: +``` +patch_mp/maps/mp/gametypes/_battlechatter.gsc +patch_mp/maps/mp/gametypes/_callbacksetup.gsc +patch_mp/maps/mp/gametypes/_class.gsc +patch_mp/maps/mp/gametypes/_copter.gsc +patch_mp/maps/mp/gametypes/_damagefeedback.gsc +patch_mp/maps/mp/gametypes/_deathicons.gsc +patch_mp/maps/mp/gametypes/_dev.gsc +patch_mp/maps/mp/gametypes/_dev_class.gsc +patch_mp/maps/mp/gametypes/_friendicons.gsc +patch_mp/maps/mp/gametypes/_gameobjects.gsc +patch_mp/maps/mp/gametypes/_globallogic.gsc +patch_mp/maps/mp/gametypes/_globallogic_actor.gsc +patch_mp/maps/mp/gametypes/_globallogic_audio.gsc +patch_mp/maps/mp/gametypes/_globallogic_defaults.gsc +patch_mp/maps/mp/gametypes/_globallogic_player.gsc +patch_mp/maps/mp/gametypes/_globallogic_score.gsc +patch_mp/maps/mp/gametypes/_globallogic_spawn.gsc +patch_mp/maps/mp/gametypes/_globallogic_ui.gsc +patch_mp/maps/mp/gametypes/_globallogic_utils.gsc +patch_mp/maps/mp/gametypes/_globallogic_vehicle.gsc +patch_mp/maps/mp/gametypes/_gv_actions.gsc +patch_mp/maps/mp/gametypes/_healthoverlay.gsc +patch_mp/maps/mp/gametypes/_hostmigration.gsc +patch_mp/maps/mp/gametypes/_hud.gsc +patch_mp/maps/mp/gametypes/_hud_message.gsc +patch_mp/maps/mp/gametypes/_hud_util.gsc +patch_mp/maps/mp/gametypes/_killcam.gsc +patch_mp/maps/mp/gametypes/_menus.gsc +patch_mp/maps/mp/gametypes/_objpoints.gsc +patch_mp/maps/mp/gametypes/_perplayer.gsc +patch_mp/maps/mp/gametypes/_persistence.gsc +patch_mp/maps/mp/gametypes/_pregame.gsc +patch_mp/maps/mp/gametypes/_rank.gsc +patch_mp/maps/mp/gametypes/_serversettings.gsc +patch_mp/maps/mp/gametypes/_spawning.gsc +patch_mp/maps/mp/gametypes/_spawnlogic.gsc +patch_mp/maps/mp/gametypes/_spectating.gsc +patch_mp/maps/mp/gametypes/_tweakables.gsc +patch_mp/maps/mp/gametypes/_wager.gsc +patch_mp/maps/mp/gametypes/_weapon_utils.gsc +patch_mp/maps/mp/gametypes/_weaponobjects.gsc +patch_mp/maps/mp/gametypes/_weapons.gsc +patch_mp/maps/mp/gametypes/conf.gsc +patch_mp/maps/mp/gametypes/ctf.gsc +patch_mp/maps/mp/gametypes/dem.gsc +patch_mp/maps/mp/gametypes/dm.gsc +patch_mp/maps/mp/gametypes/dom.gsc +patch_mp/maps/mp/gametypes/gun.gsc +patch_mp/maps/mp/gametypes/hq.gsc +patch_mp/maps/mp/gametypes/koth.gsc +patch_mp/maps/mp/gametypes/oic.gsc +patch_mp/maps/mp/gametypes/oneflag.gsc +patch_mp/maps/mp/gametypes/sas.gsc +patch_mp/maps/mp/gametypes/sd.gsc +patch_mp/maps/mp/gametypes/shrp.gsc +patch_mp/maps/mp/gametypes/tdm.gsc +``` +### notes: +``` +``` + +