From 1b4967c15099bab7e759810d39792a30d394836d Mon Sep 17 00:00:00 2001 From: JezuzLizard Date: Thu, 29 Jul 2021 06:47:24 -0700 Subject: [PATCH] Added more scripts for potential optimization. --- .gitignore | 4 + .../maps/mp/gametypes_zm/_globallogic.gsc | 2741 ++++++++++++ .../maps/mp/gametypes_zm/_weapons.gsc | 1950 ++++++++ .../maps/mp/gametypes_zm/_zm_gametype.gsc | 1997 +++++++++ .../maps/mp/zombies/_zm_buildables.gsc | 3146 +++++++++++++ .../maps/mp/zombies/_zm_chugabud.gsc | 805 ++++ .../maps/mp/zombies/_zm_equipment.gsc | 1905 ++++++++ .../maps/mp/zombies/_zm_perks.gsc | 3931 +++++++++++++++++ .../maps/mp/zombies/_zm_powerups.gsc | 2862 ++++++++++++ .../maps/mp/zombies/_zm_spawner.gsc | 3290 ++++++++++++++ .../maps/mp/zombies/_zm_weapons.gsc | 2807 ++++++++++++ .../maps/mp/zombies/_zm_zonemgr.gsc | 62 +- 12 files changed, 25469 insertions(+), 31 deletions(-) create mode 100644 .gitignore create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_globallogic.gsc create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_weapons.gsc create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_zm_gametype.gsc create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_buildables.gsc create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_chugabud.gsc create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_equipment.gsc create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_perks.gsc create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_powerups.gsc create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_spawner.gsc create mode 100644 Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_weapons.gsc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ba5abd --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ + +*.json +.vs/Recompilable-gscs-for-BO2-zombies/v16/.suo +*.sqlite diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_globallogic.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_globallogic.gsc new file mode 100644 index 0000000..9af0f50 --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_globallogic.gsc @@ -0,0 +1,2741 @@ +#include maps/mp/gametypes_zm/_globallogic; +#include maps/mp/gametypes_zm/_hostmigration; +#include maps/mp/gametypes_zm/_dev; +#include maps/mp/gametypes_zm/_friendicons; +#include maps/mp/gametypes_zm/_healthoverlay; +#include maps/mp/gametypes_zm/_damagefeedback; +#include maps/mp/teams/_teams; +#include maps/mp/_decoy; +#include maps/mp/gametypes_zm/_spawnlogic; +#include maps/mp/gametypes_zm/_gameobjects; +#include maps/mp/gametypes_zm/_objpoints; +#include maps/mp/gametypes_zm/_spectating; +#include maps/mp/gametypes_zm/_deathicons; +#include maps/mp/gametypes_zm/_shellshock; +#include maps/mp/gametypes_zm/_scoreboard; +#include maps/mp/gametypes_zm/_weaponobjects; +#include maps/mp/gametypes_zm/_clientids; +#include maps/mp/gametypes_zm/_serversettings; +#include maps/mp/_challenges; +#include maps/mp/_music; +#include maps/mp/gametypes_zm/_weapons; +#include maps/mp/gametypes_zm/_globallogic_player; +#include maps/mp/_demo; +#include maps/mp/killstreaks/_killstreaks; +#include maps/mp/gametypes_zm/_wager; +#include maps/mp/gametypes_zm/_persistence; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/gametypes_zm/_globallogic_utils; +#include maps/mp/gametypes_zm/_hud_message; +#include maps/mp/gametypes_zm/_globallogic_defaults; +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/gametypes_zm/_globallogic_spawn; +#include maps/mp/_gamerep; +#include maps/mp/_gameadvertisement; +#include maps/mp/gametypes_zm/_globallogic_audio; +#include maps/mp/gametypes_zm/_class; +#include maps/mp/gametypes_zm/_globallogic_ui; +#include maps/mp/gametypes_zm/_tweakables; +#include common_scripts/utility; +#include maps/mp/_busing; +#include maps/mp/_burnplayer; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/_utility; + +init() //checked matches bo3 _globallogic.gsc within reason +{ + + // hack to allow maps with no scripts to run correctly + if ( !isDefined( level.tweakablesInitialized ) ) + maps\mp\gametypes_zm\_tweakables::init(); + + init_session_mode_flags(); + + level.splitscreen = isSplitScreen(); + level.xenon = 0; + level.ps3 = 0; + level.wiiu = 0; + + level.onlineGame = SessionModeIsOnlineGame(); + level.console = 1; + + level.rankedMatch = 0; + level.leagueMatch = 0; + + level.wagerMatch = false; + + level.contractsEnabled = !GetGametypeSetting( "disableContracts" ); + + level.contractsEnabled = false; + + /* +/# + if ( GetDvarint( "scr_forcerankedmatch" ) == 1 ) + level.rankedMatch = true; +#/ + */ + + level.script = toLower( GetDvar( "mapname" ) ); + level.gametype = toLower( GetDvar( "g_gametype" ) ); + + level.teamBased = false; + level.teamCount = GetGametypeSetting( "teamCount" ); + level.multiTeam = ( level.teamCount > 2 ); + + if ( 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; + } + } + + // used to loop through all valid playing teams ( not spectator ) + // can also be used to check if a team is valid ( isdefined( level.teams[team] ) ) + // NOTE: added in the same order they are defined in code + level.teams = []; + level.teamIndex = []; + + teamCount = level.teamCount; + + level.teams[ "allies" ] = "allies"; + level.teams[ "axis" ] = "axis"; + + level.teamIndex[ "neutral" ] = 0; // Neutral team set to 0 so that it can be used by objectives + level.teamIndex[ "allies" ] = 1; + level.teamIndex[ "axis" ] = 2; + + for( teamIndex = 3; teamIndex <= teamCount; teamIndex++ ) + { + level.teams[ "team" + teamIndex ] = "team" + teamIndex; + level.teamIndex[ "team" + teamIndex ] = teamIndex; + } + + level.overrideTeamScore = false; + level.overridePlayerScore = false; + level.displayHalftimeText = false; + level.displayRoundEndText = true; + + level.endGameOnScoreLimit = true; + level.endGameOnTimeLimit = true; + level.scoreRoundBased = false; + level.resetPlayerScoreEveryRound = false; + + level.gameForfeited = false; + level.forceAutoAssign = false; + + level.halftimeType = "halftime"; + level.halftimeSubCaption = &"MP_SWITCHING_SIDES_CAPS"; + + level.lastStatusTime = 0; + level.wasWinning = []; + + level.lastSlowProcessFrame = 0; + + level.placement = []; + foreach ( team in level.teams ) + { + level.placement[team] = []; + } + level.placement["all"] = []; + + level.postRoundTime = 7.0;//Kevin Sherwood changed to 9 to have enough time for music stingers + + level.inOvertime = false; + + level.defaultOffenseRadius = 560; + + level.dropTeam = GetDvarint( "sv_maxclients" ); + + level.inFinalKillcam = false; + + maps\mp\gametypes_zm\_globallogic_ui::init(); + + registerDvars(); +// maps\mp\gametypes_zm\_class::initPerkDvars(); + + level.oldschool = ( GetDvarint( "scr_oldschool" ) == 1 ); + if ( level.oldschool ) + { + SetDvar( "jump_height", 64 ); + SetDvar( "jump_slowdownEnable", 0 ); + SetDvar( "bg_fallDamageMinHeight", 256 ); + SetDvar( "bg_fallDamageMaxHeight", 512 ); + SetDvar( "player_clipSizeMultiplier", 2.0 ); + } + + precacheModel( "tag_origin" ); + precacheRumble( "dtp_rumble" ); + precacheRumble( "slide_rumble" ); + + precacheStatusIcon( "hud_status_dead" ); + precacheStatusIcon( "hud_status_connecting" ); + + precache_mp_leaderboards(); + + // sets up the flame fx + //maps\mp\_burnplayer::initBurnPlayer(); + + if ( !isDefined( game["tiebreaker"] ) ) + game["tiebreaker"] = false; + + maps\mp\gametypes_zm\_globallogic_audio::registerDialogGroup( "introboost", true ); + maps\mp\gametypes_zm\_globallogic_audio::registerDialogGroup( "status", true ); + + //thread maps\mp\_gameadvertisement::init(); + //thread maps\mp\_gamerep::init(); +} + +registerDvars() //checked matches bo3 _globallogic.gsc within reason +{ + if ( GetDvar( "scr_oldschool" ) == "" ) + SetDvar( "scr_oldschool", "0" ); + + makeDvarServerInfo( "scr_oldschool" ); + + if ( GetDvar( "ui_guncycle" ) == "" ) + SetDvar( "ui_guncycle", 0 ); + + makedvarserverinfo( "ui_guncycle" ); + + if ( GetDvar( "ui_weapon_tiers" ) == "" ) + 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( "scr_vehicle_damage_scalar" ) == "" ) + SetDvar( "scr_vehicle_damage_scalar", "1" ); + + level.vehicleDamageScalar = GetDvarfloat( "scr_vehicle_damage_scalar"); + + level.fire_audio_repeat_duration = GetDvarint( "fire_audio_repeat_duration" ); + level.fire_audio_random_max_duration = GetDvarint( "fire_audio_random_max_duration" ); +} + +blank( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 ) //checked matches bo3 _globallogic.gsc within reason +{ +} + +SetupCallbacks() //checked matches bo3 _globallogic.gsc within reason +{ + level.spawnPlayer = maps\mp\gametypes_zm\_globallogic_spawn::spawnPlayer; + level.spawnPlayerPrediction = maps\mp\gametypes_zm\_globallogic_spawn::spawnPlayerPrediction; + level.spawnClient = maps\mp\gametypes_zm\_globallogic_spawn::spawnClient; + level.spawnSpectator = maps\mp\gametypes_zm\_globallogic_spawn::spawnSpectator; + level.spawnIntermission = maps\mp\gametypes_zm\_globallogic_spawn::spawnIntermission; + level.onPlayerScore = maps\mp\gametypes_zm\_globallogic_score::default_onPlayerScore; + level.onTeamScore = maps\mp\gametypes_zm\_globallogic_score::default_onTeamScore; + + level.waveSpawnTimer = ::waveSpawnTimer; + level.spawnMessage = maps\mp\gametypes_zm\_globallogic_spawn::default_spawnMessage; + + level.onSpawnPlayer = ::blank; + level.onSpawnPlayerUnified = ::blank; + level.onSpawnSpectator = maps\mp\gametypes_zm\_globallogic_defaults::default_onSpawnSpectator; + level.onSpawnIntermission = maps\mp\gametypes_zm\_globallogic_defaults::default_onSpawnIntermission; + level.onRespawnDelay = ::blank; + + level.onForfeit = maps\mp\gametypes_zm\_globallogic_defaults::default_onForfeit; + level.onTimeLimit = maps\mp\gametypes_zm\_globallogic_defaults::default_onTimeLimit; + level.onScoreLimit = maps\mp\gametypes_zm\_globallogic_defaults::default_onScoreLimit; + level.onAliveCountChange = maps\mp\gametypes_zm\_globallogic_defaults::default_onAliveCountChange; + level.onDeadEvent = maps\mp\gametypes_zm\_globallogic_defaults::default_onDeadEvent; + level.onOneLeftEvent = maps\mp\gametypes_zm\_globallogic_defaults::default_onOneLeftEvent; + level.giveTeamScore = maps\mp\gametypes_zm\_globallogic_score::giveTeamScore; + level.onLastTeamAliveEvent = undefined; + + level.getTimeLimit = maps\mp\gametypes_zm\_globallogic_defaults::default_getTimeLimit; + level.getTeamKillPenalty =::blank; // maps\mp\gametypes_zm\_globallogic_defaults::default_getTeamKillPenalty; + level.getTeamKillScore = ::blank; // maps\mp\gametypes_zm\_globallogic_defaults::default_getTeamKillScore; + + level.isKillBoosting = maps\mp\gametypes_zm\_globallogic_score::default_isKillBoosting; + + level._setTeamScore = maps\mp\gametypes_zm\_globallogic_score::_setTeamScore; + level._setPlayerScore = maps\mp\gametypes_zm\_globallogic_score::_setPlayerScore; + + level._getTeamScore = maps\mp\gametypes_zm\_globallogic_score::_getTeamScore; + level._getPlayerScore = maps\mp\gametypes_zm\_globallogic_score::_getPlayerScore; + + level.onPrecacheGametype = ::blank; + level.onStartGameType = ::blank; + level.onPlayerConnect = ::blank; + level.onPlayerDisconnect = ::blank; + level.onPlayerDamage = ::blank; + level.onPlayerKilled = ::blank; + level.onPlayerKilledExtraUnthreadedCBs = []; //< Array of other CB function pointers + + level.onTeamOutcomeNotify = maps\mp\gametypes_zm\_hud_message::teamOutcomeNotify; + level.onOutcomeNotify = maps\mp\gametypes_zm\_hud_message::outcomeNotify; + level.onTeamWagerOutcomeNotify = maps\mp\gametypes_zm\_hud_message::teamWagerOutcomeNotify; + level.onWagerOutcomeNotify = maps\mp\gametypes_zm\_hud_message::wagerOutcomeNotify; + level.setMatchScoreHUDElemForTeam = maps\mp\gametypes_zm\_hud_message::setMatchScoreHUDElemForTeam; + level.onEndGame = ::blank; + level.onRoundEndGame = maps\mp\gametypes_zm\_globallogic_defaults::default_onRoundEndGame; + level.onMedalAwarded = ::blank; + + maps\mp\gametypes_zm\_globallogic_ui::SetupCallbacks(); +} + +precache_mp_leaderboards() //checked matches bo3 _globallogic.gsc within reason +{ + if( SessionModeIsZombiesGame() ) + return; + + if( !level.rankedMatch ) + return; + + mapname = GetDvar( "mapname" ); + + globalLeaderboards = "LB_MP_GB_XPPRESTIGE LB_MP_GB_TOTALXP_AT LB_MP_GB_TOTALXP_LT LB_MP_GB_WINS_AT LB_MP_GB_WINS_LT LB_MP_GB_KILLS_AT LB_MP_GB_KILLS_LT LB_MP_GB_ACCURACY_AT LB_MP_GB_ACCURACY_LT"; + + gamemodeLeaderboard = " LB_MP_GM_" + level.gametype; + + if( getDvarInt( "g_hardcore" ) ) + gamemodeLeaderboard += "_HC"; + + mapLeaderboard = " LB_MP_MAP_" + getsubstr( mapname, 3, mapname.size ); // strip the MP_ from the map name + + precacheLeaderboards( globalLeaderboards + gamemodeLeaderboard + mapLeaderboard ); +} + +compareTeamByGameStat( gameStat, teamA, teamB, previous_winner_score ) //checked matches bo3 _globallogic.gsc within reason +{ + 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 ) //checked matches bo3 _globallogic.gsc within reason +{ + teamKeys = GetArrayKeys(level.teams); + winner = teamKeys[0]; + previous_winner_score = game[gameStat][winner]; + + for ( teamIndex = 1; teamIndex < teamKeys.size; teamIndex++ ) + { + winner = compareTeamByGameStat( gameStat, winner, teamKeys[teamIndex], previous_winner_score); + + if ( winner != "tie" ) + { + previous_winner_score = game[gameStat][winner]; + } + } + + return winner; +} + +compareTeamByTeamScore( teamA, teamB, previous_winner_score ) //checked matches bo3 _globallogic.gsc within reason +{ + 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( ) //checked matches bo3 _globallogic.gsc within reason +{ + teamKeys = GetArrayKeys(level.teams); + winner = teamKeys[0]; + previous_winner_score = [[level._getTeamScore]]( winner ); + + for ( teamIndex = 1; teamIndex < teamKeys.size; teamIndex++ ) + { + winner = compareTeamByTeamScore( winner, teamKeys[teamIndex], previous_winner_score); + + if ( winner != "tie" ) + { + previous_winner_score = [[level._getTeamScore]]( winner ); + } + } + + return winner; +} + +forceEnd(hostsucks) //checked matches bo3 _globallogic.gsc within reason +{ + if ( !isDefined(hostsucks ) ) + hostsucks = false; + + if ( level.hostForcedEnd || level.forcedEnd ) + return; + + winner = undefined; + + if ( level.teamBased ) + { + winner = determineTeamWinnerByGameStat("teamScores"); + maps\mp\gametypes_zm\_globallogic_utils::logTeamWinString( "host ended game", winner ); + } + else + { + winner = maps\mp\gametypes_zm\_globallogic_score::getHighestScoringPlayer(); + if ( isDefined( winner ) ) + logString( "host ended game, win: " + winner.name ); + else + logString( "host ended game, tie" ); + } + + level.forcedEnd = true; + level.hostForcedEnd = true; + + 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() //checked matches bo3 _globallogic.gsc within reason +{ + if ( level.hostForcedEnd || level.forcedEnd ) + return; + + winner = undefined; + + if ( level.teamBased ) + { + winner = determineTeamWinnerByGameStat("teamScores"); + maps\mp\gametypes_zm\_globallogic_utils::logTeamWinString( "host ended game", winner ); + } + else + { + winner = maps\mp\gametypes_zm\_globallogic_score::getHighestScoringPlayer(); + if ( isDefined( winner ) ) + logString( "host ended game, win: " + winner.name ); + else + logString( "host ended game, tie" ); + } + + level.forcedEnd = true; + level.hostForcedEnd = true; + + level.killserver = true; + + endString = &"MP_HOST_ENDED_GAME"; + + /* +/# + PrintLn("kill server; ending game\n"); +#/ + */ + thread endGame( winner, endString ); +} + +someoneOnEachTeam() //checked matches bo3 _globallogic.gsc within reason +{ + foreach ( team in level.teams ) + { + if ( level.playerCount[team] == 0 ) + return false; + } + + return true; +} + +checkIfTeamForfeits( team ) //checked matches bo3 _globallogic.gsc within reason +{ + if ( !level.everExisted[team] ) + return false; + + if ( level.playerCount[team] < 1 && totalPlayerCount() > 0 ) + { + return true; + } + + return false; +} + +checkForAnyTeamForfeit() //checked matches bo3 _globallogic.gsc within reason +{ + foreach( team in level.teams ) + { + if ( checkIfTeamForfeits( team ) ) + { + //allies forfeited + thread [[level.onForfeit]]( team ); + return true; + } + } + + return false; +} + +doSpawnQueueUpdates() //checked matches bo3 _globallogic.gsc within reason +{ + foreach( team in level.teams ) + { + if ( level.spawnQueueModified[team] ) + { + [[level.onAliveCountChange]]( team ); + } + } +} + +isTeamAllDead( team ) //checked changed at own discretion +{ + if ( level.everExisted[team] && !level.aliveCount[ team ] && !level.playerLives[ team ] ) + { + return 1; + } + return 0; +} + +areAllTeamsDead( ) //checked matches bo3 _globallogic.gsc within reason +{ + foreach( team in level.teams ) + { + // if team was alive and now they are not + if ( !isTeamAllDead( team ) ) + { + return false; + } + } + + return true; +} + +allDeadTeamCount( ) //checked matches bo3 _globallogic.gsc within reason +{ + count = 0; + foreach( team in level.teams ) + { + // if team was alive and now they are not + if ( isTeamAllDead( team ) ) + { + count++; + } + } + + return count; +} + +doDeadEventUpdates() //checked matches bo3 _globallogic.gsc within reason +{ + if ( level.teamBased ) + { + // if all teams were alive and now they are all dead in the same instance + if ( areAllTeamsDead( ) ) + { + [[level.onDeadEvent]]( "all" ); + return true; + } + + // TODO MTEAM - invert all onDeadEvent functions to be onLastTeamAliveEvent instead + if ( isdefined( level.onLastTeamAliveEvent ) ) + { + if ( allDeadTeamCount( ) == level.teams.size - 1 ) + { + foreach( team in level.teams ) + { + // if team is alive + if ( !isTeamAllDead( team ) ) + { + [[level.onLastTeamAliveEvent]]( team ); + return true; + } + } + } + } + else + { + foreach( team in level.teams ) + { + // if team was alive and now they are not + if ( isTeamAllDead( team ) ) + { + [[level.onDeadEvent]]( team ); + return true; + } + } + } + } + else + { + // everyone is dead + if ( (totalAliveCount() == 0) && (totalPlayerLives() == 0) && level.maxPlayerCount > 1 ) + { + [[level.onDeadEvent]]( "all" ); + return true; + } + } + + return false; +} + +isOnlyOneLeftAliveOnTeam( team ) //checked changed at own discretion +{ + if ( level.lastAliveCount[team] > 1 && level.aliveCount[team] == 1 && level.playerLives[team] == 1 ) + { + return 1; + } + return 0; +} + + +doOneLeftEventUpdates() //checked matches bo3 _globallogic.gsc within reason +{ + if ( level.teamBased ) + { + foreach( team in level.teams ) + { + // one "team" left + if ( isOnlyOneLeftAliveOnTeam( team ) ) + { + [[level.onOneLeftEvent]]( team ); + return true; + } + } + } + else + { + // last man standing + if ( (totalAliveCount() == 1) && (totalPlayerLives() == 1) && level.maxPlayerCount > 1 ) + { + [[level.onOneLeftEvent]]( "all" ); + return true; + } + } + + return false; +} + +updateGameEvents() //checked matches bo3 _globallogic.gsc within reason +{ + /* +/# + if( GetDvarint( "scr_hostmigrationtest" ) == 1 ) + { + return; + } +#/ + */ + if ( !level.inGracePeriod ) + { + if ( level.teamBased ) + { + if (!level.gameForfeited ) + { + if( game["state"] == "playing" && checkForAnyTeamForfeit() ) + { + return; + } + } + else // level.gameForfeited==true + { + if ( someoneOnEachTeam() ) + { + level.gameForfeited = false; + level notify( "abort forfeit" ); + } + } + } + else + { + if (!level.gameForfeited) + { + if ( totalPlayerCount() == 1 && level.maxPlayerCount > 1 ) + { + thread [[level.onForfeit]](); + return; + } + } + else // level.gameForfeited==true + { + if ( totalPlayerCount() > 1 ) + { + level.gameForfeited = false; + level notify( "abort forfeit" ); + } + } + } + } + + if ( !level.playerQueuedRespawn && !level.numLives && !level.inOverTime ) + return; + + if ( level.inGracePeriod ) + return; + + if ( level.playerQueuedRespawn ) + { + doSpawnQueueUpdates(); + } + + if ( doDeadEventUpdates() ) + return; + + if ( doOneLeftEventUpdates() ) + return; +} + + +matchStartTimer() //checked matches bo3 _globallogic.gsc within reason +{ + 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 = false; + matchStartText.hidewheninmenu = true; + + waitForPlayers(); + matchStartText setText( game["strings"]["match_starting_in"] ); + + matchStartTimer = createServerFontString( "objective", 2.2 ); + matchStartTimer setPoint( "CENTER", "CENTER", 0, 0 ); + matchStartTimer.sort = 1001; + matchStartTimer.color = (1,1,0); + matchStartTimer.foreground = false; + matchStartTimer.hidewheninmenu = true; + + + //Since the scaling is disabled, we cant see the pulse effect by scaling. We need to change keep switching between + //some small and big font to get the pulse effect. This will be fixed when we have fixed set of different sizes fonts. + + //matchStartTimer maps\mp\gametypes_zm\_hud::fontPulseInit(); + + countTime = int( level.prematchPeriod ); + + if ( countTime >= 2 ) + { + while ( countTime > 0 && !level.gameEnded ) + { + matchStartTimer setValue( countTime ); + //matchStartTimer thread maps\mp\gametypes_zm\_hud::fontPulse( level ); + if ( countTime == 2 ) + visionSetNaked( GetDvar( "mapname" ), 3.0 ); + countTime--; + wait ( 1.0 ); + } + } + else + { + visionSetNaked( GetDvar( "mapname" ), 1.0 ); + } + + matchStartTimer destroyElem(); + matchStartText destroyElem(); +} + +matchStartTimerSkip() //checked matches bo3 _globallogic.gsc within reason +{ + if ( !isPregame() ) + visionSetNaked( GetDvar( "mapname" ), 0 ); + else + visionSetNaked( "mpIntro", 0 ); +} + +notifyTeamWaveSpawn( team, time ) //checked matches bo3 _globallogic.gsc within reason +{ + if ( time - level.lastWave[team] > (level.waveDelay[team] * 1000) ) + { + level notify ( "wave_respawn_" + team ); + level.lastWave[team] = time; + level.wavePlayerSpawnIndex[team] = 0; + } +} + +waveSpawnTimer() //checked matches bo3 _globallogic.gsc within reason +{ + level endon( "game_ended" ); + + while ( game["state"] == "playing" ) + { + time = getTime(); + + foreach( team in level.teams ) + { + notifyTeamWaveSpawn( team, time ); + } + wait ( 0.05 ); + } +} + + +hostIdledOut() //checked matches bo3 _globallogic.gsc within reason +{ + hostPlayer = getHostPlayer(); + /* +/# + if( GetDvarint( "scr_writeconfigstrings" ) == 1 || GetDvarint( "scr_hostmigrationtest" ) == 1 ) + return false; +#/ + */ + // host never spawned + if ( isDefined( hostPlayer ) && !hostPlayer.hasSpawned && !isDefined( hostPlayer.selectedClass ) ) + return true; + + return false; +} + +IncrementMatchCompletionStat( gameMode, playedOrHosted, stat ) //checked matches bo3 _globallogic.gsc within reason +{ + self AddDStat( "gameHistory", gameMode, "modeHistory", playedOrHosted, stat, 1 ); +} + +SetMatchCompletionStat( gameMode, playedOrHosted, stat ) //checked matches bo3 _globallogic.gsc within reason +{ + self SetDStat( "gameHistory", gameMode, "modeHistory", playedOrHosted, stat, 1 ); +} + +GetCurrentGameMode() //doesn't exist in bo3 _globallogic.gsc leaving in +{ + return "publicmatch"; +} + +displayRoundEnd( winner, endReasonText ) //checked matches bo3 _globallogic.gsc within reason changed for loop to while loop see github for more info +{ + if ( level.displayRoundEndText ) + { + 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 ( !isDefined( player.pers["team"] ) ) + { + player [[level.spawnIntermission]]( true ); + player closeMenu(); + player closeInGameMenu(); + index++; + continue; + } + + if ( level.wagerMatch ) + { + if ( level.teamBased ) + player thread [[level.onTeamWagerOutcomeNotify]]( winner, true, endReasonText ); + else + player thread [[level.onWagerOutcomeNotify]]( winner, endReasonText ); + } + else + { + if ( level.teamBased ) + { + player thread [[level.onTeamOutcomeNotify]]( winner, true, endReasonText ); + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "ROUND_END" ); + } + else + { + player thread [[level.onOutcomeNotify]]( winner, true, endReasonText ); + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "ROUND_END" ); + } + } + + player setClientUIVisibilityFlag( "hud_visible", 0 ); + player setClientUIVisibilityFlag( "g_compassShowEnemies", 0 ); + index++; + } + } + + if ( wasLastRound() ) + { + roundEndWait( level.roundEndDelay, false ); + } + else + { + thread maps\mp\gametypes_zm\_globallogic_audio::announceRoundWinner( winner, level.roundEndDelay / 4 ); + roundEndWait( level.roundEndDelay, true ); + } +} + +displayRoundSwitch( winner, endReasonText ) //checked matches bo3 _globallogic.gsc within reason changed for loop to while loop see github for more info +{ + 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_zm\_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]]( true ); + player closeMenu(); + player closeInGameMenu(); + index++ + continue; + } + + player maps\mp\gametypes_zm\_globallogic_audio::leaderDialogOnPlayer( leaderdialog ); + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "ROUND_SWITCH" ); + + if ( level.wagerMatch ) + player thread [[level.onTeamWagerOutcomeNotify]]( switchType, true, level.halftimeSubCaption ); + else + player thread [[level.onTeamOutcomeNotify]]( switchType, false, level.halftimeSubCaption ); + player setClientUIVisibilityFlag( "hud_visible", 0 ); + index++; + } + + roundEndWait( level.halftimeRoundEndDelay, false ); +} + +displayGameEnd( winner, endReasonText ) //checked matches bo3 _globallogic.gsc within reason changed for loop to while loop see github for more info +{ + SetMatchTalkFlag( "EveryoneHearsEveryone", 1 ); + setmatchflag( "cg_drawSpectatorMessages", 0 ); + + 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" ] ); + } + + // catching gametype, since DM forceEnd sends winner as player entity, instead of string + players = level.players; + index = 0; + while ( index < players.size ) + { + player = players[index]; + + if ( !isDefined( player.pers["team"] ) ) + { + player [[level.spawnIntermission]]( true ); + player closeMenu(); + player closeInGameMenu(); + index++; + continue; + } + + if ( level.wagerMatch ) + { + if ( level.teamBased ) + player thread [[level.onTeamWagerOutcomeNotify]]( winner, false, endReasonText ); + else + player thread [[level.onWagerOutcomeNotify]]( winner, endReasonText ); + } + else + { + if ( level.teamBased ) + { + player thread [[level.onTeamOutcomeNotify]]( winner, false, endReasonText ); + } + else + { + player thread [[level.onOutcomeNotify]]( winner, false, endReasonText ); + + if ( isDefined( winner ) && player == winner ) + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "VICTORY" ); + else if ( !level.splitScreen ) + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "LOSE" ); + } + } + + player setClientUIVisibilityFlag( "hud_visible", 0 ); + player setClientUIVisibilityFlag( "g_compassShowEnemies", 0 ); + index++; + } + + if ( level.teamBased ) + { + thread maps\mp\gametypes_zm\_globallogic_audio::announceGameWinner( winner, level.postRoundTime / 2 ); + + players = level.players; + for ( index = 0; index < players.size; index++ ) + { + player = players[index]; + team = player.pers["team"]; + + if ( level.splitscreen ) + { + if ( winner == "tie" ) + { + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "DRAW" ); + } + else if ( winner == team ) + { + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "VICTORY" ); + } + else + { + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "LOSE" ); + } + } + else + { + if ( winner == "tie" ) + { + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "DRAW" ); + } + else if ( winner == team ) + { + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "VICTORY" ); + } + else + { + player maps\mp\gametypes_zm\_globallogic_audio::set_music_on_player( "LOSE" ); + } + } + } + } + + bbPrint( "session_epilogs", "reason %s", endReasonText ); + + // tagTMR: all round data aggregates that cannot be summed from other tables post-runtime + bbPrint( "mpmatchfacts", "gametime %d winner %s killstreakcount %d", gettime(), winner, level.killstreak_counter ); + + roundEndWait( level.postRoundTime, true ); +} + +getEndReasonText() //checked matches bo3 _globallogic.gsc within reason +{ + 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() //checked matches bo3 _globallogic.gsc within reason +{ + players = level.players; + for ( index = 0; index < players.size; index++ ) + { + player = players[index]; + player notify ( "reset_outcome" ); + } +} + +startNextRound( winner, endReasonText ) //checked matches bo3 _globallogic.gsc within reason +{ + if ( !isOneRound() ) + { + displayRoundEnd( winner, endReasonText ); + + maps\mp\gametypes_zm\_globallogic_utils::executePostRoundEvents(); + + if ( !wasLastRound() ) + { + if ( 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( true ); + return true; + } + } + return false; +} + + +setTopPlayerStats( ) //doesn't exist in bo3 _globallogic.gsc leaving in +{ + if( level.rankedMatch || level.wagerMatch ) + { + placement = level.placement["all"]; + topThreePlayers = min( 3, placement.size ); + + for ( index = 0; index < topThreePlayers; index++ ) + { + 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] notify( "top3" ); + } + } + + for ( index = 3 ; index < placement.size ; index++ ) + { + level.placement["all"][index] notify( "nottop3" ); + level.placement["all"][index] notify( "nottopplayer" ); + } + + if ( level.teambased ) + { + foreach ( team in level.teams ) + { + setTopTeamStats(team); + } + } + } +} + +setTopTeamStats(team) //doesn't exist in bo3 _globallogic.gsc leaving in +{ + placementTeam = level.placement[team]; + topThreeTeamPlayers = min( 3, placementTeam.size ); + // should have at least 5 players on the team + if ( placementTeam.size < 5 ) + return; + + for ( index = 0; index < topThreeTeamPlayers; index++ ) + { + if ( placementTeam[index].score ) + { + //placementTeam[index] AddPlayerStat( "BASIC_TOP_3_TEAM", 1 ); + placementTeam[index] AddPlayerStatWithGameType( "TOP3TEAM", 1 ); + } + } +} + +getGameLength() //checked matches bo3 _globallogic.gsc within reason +{ + if ( !level.timeLimit || level.forcedEnd ) + { + gameLength = maps\mp\gametypes_zm\_globallogic_utils::getTimePassed() / 1000; + // cap it at 20 minutes to avoid exploiting + gameLength = min( gameLength, 1200 ); + } + else + { + gameLength = level.timeLimit * 60; + } + + return gameLength; +} + +gameHistoryPlayerQuit() //checked matches bo3 _globallogic.gsc within reason +{ + if ( !GameModeIsMode( level.GAMEMODE_PUBLIC_MATCH ) ) + return; + + teamScoreRatio = 0; + self GameHistoryFinishMatch( MATCH_QUIT, 0, 0, 0, 0, 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 ); + + // wait until the player recieves the new stats + wait(1); +} + +endGame( winner, endReasonText ) //checked matches bo3 _globallogic.gsc within reason changed for loop to while loop see github for more info +{ + // return if already ending via host quit or victory + if ( game["state"] == "postgame" || level.gameEnded ) + return; + + if ( isDefined( level.onEndGame ) ) + [[level.onEndGame]]( winner ); + + //This wait was added possibly for wager match issues, but we think is no longer necessary. + //It was creating issues with multiple players calling this fuction when checking game score. In modes like HQ, + //The game score is given to every player on the team that captured the HQ, so when the points are dished out it loops through + //all players on that team and checks if the score limit has been reached. But since this wait occured before the game["state"] + //could be set to "postgame" the check score thread would send the next player that reached the score limit into this function, + //when the following code should only be hit once. If this wait turns out to be needed, we need to try pulling the game["state"] = "postgame"; + //up above the wait. + //wait 0.05; + + if ( !level.wagerMatch ) + setMatchFlag( "enable_popups", 0 ); + if ( !isdefined( level.disableOutroVisionSet ) || level.disableOutroVisionSet == false ) + { + if ( SessionModeIsZombiesGame() && level.forcedEnd ) + { + visionSetNaked( "zombie_last_stand", 2.0 ); + } + else + { + visionSetNaked( "mpOutro", 2.0 ); + } + } + + setmatchflag( "cg_drawSpectatorMessages", 0 ); + setmatchflag( "game_ended", 1 ); + + game["state"] = "postgame"; + level.gameEndTime = getTime(); + level.gameEnded = true; + SetDvar( "g_gameEnded", 1 ); + level.inGracePeriod = false; + level notify ( "game_ended" ); + level.allowBattleChatter = false; + maps\mp\gametypes_zm\_globallogic_audio::flushDialog(); + + if ( !IsDefined( game["overtime_round"] ) || wasLastRound() ) // Want to treat all overtime rounds as a single round + { + game["roundsplayed"]++; + game["roundwinner"][game["roundsplayed"]] = winner; + + //Added "if" check for FFA - Leif + if( level.teambased ) + { + game["roundswon"][winner]++; + } + } + + if ( isdefined( winner ) && isdefined( level.teams[winner] ) ) + { + level.finalKillCam_winner = winner; + } + else + { + level.finalKillCam_winner = "none"; + } + + setGameEndTime( 0 ); // stop/hide the timers + + updatePlacement(); + + updateRankedMatch( winner ); + + // freeze players + players = level.players; + + newTime = getTime(); + gameLength = getGameLength(); + + SetMatchTalkFlag( "EveryoneHearsEveryone", 1 ); + + bbGameOver = 0; + if ( isOneRound() || wasLastRound() ) + { + bbGameOver = 1; + + if ( level.teambased ) + { + if ( winner == "tie" ) + { + recordGameResult( "draw" ); + } + else + { + recordGameResult( winner ); + } + } + else + { + if ( !isDefined( winner ) ) + { + recordGameResult( "draw" ); + } + else + { + recordGameResult( winner.team ); + } + } + } + + index = 0; + while ( index < players.size ) + { + player = players[index]; + player maps\mp\gametypes_zm\_globallogic_player::freezePlayerForRoundEnd(); + player thread roundEndDoF( 4.0 ); + + player maps\mp\gametypes_zm\_globallogic_ui::freeGameplayHudElems(); + + // Update weapon usage stats + player maps\mp\gametypes_zm\_weapons::updateWeaponTimings( newTime ); + + player bbPlayerMatchEnd( gameLength, endReasonText, bbGameOver ); + + if( isPregame() ) + { + index++; + continue; + } + + if( level.rankedMatch || level.wagerMatch || level.leagueMatch ) + { + if ( isDefined( player.setPromotion ) ) + { + player setDStat( "AfterActionReportStats", "lobbyPopup", "promotion" ); + } + else + { + player setDStat( "AfterActionReportStats", "lobbyPopup", "summary" ); + } + } + index++; + } + + maps\mp\_music::setmusicstate( "SILENT" ); + +// temporarily disabling round end sound call to prevent the final killcam from not having sound + if ( !level.inFinalKillcam ) + { +// clientnotify ( "snd_end_rnd" ); + } + + //maps\mp\_gamerep::gameRepUpdateInformationForRound(); +// maps\mp\gametypes_zm\_wager::finalizeWagerRound(); +// maps\mp\gametypes_zm\_gametype_variants::onRoundEnd(); + thread maps\mp\_challenges::roundEnd( winner ); + + if ( startNextRound( winner, endReasonText ) ) + { + return; + } + + /////////////////////////////////////////// + // After this the match is really ending // + /////////////////////////////////////////// + + if ( !isOneRound() ) + { + if ( isDefined( level.onRoundEndGame ) ) + { + winner = [[level.onRoundEndGame]]( winner ); + } + + endReasonText = getEndReasonText(); + } + + skillUpdate( winner, level.teamBased ); + recordLeagueWinner( winner ); + + setTopPlayerStats(); + thread maps\mp\_challenges::gameEnd( winner ); + + if ( ( !isDefined( level.skipGameEnd ) || !level.skipGameEnd ) && IsDefined( winner ) ) + displayGameEnd( winner, endReasonText ); + + if ( isOneRound() ) + { + maps\mp\gametypes_zm\_globallogic_utils::executePostRoundEvents(); + } + + level.intermission = true; + + //maps\mp\_gamerep::gameRepAnalyzeAndReport(); + +// maps\mp\gametypes_zm\_wager::finalizeWagerGame(); + + SetMatchTalkFlag( "EveryoneHearsEveryone", 1 ); + + //regain players array since some might've disconnected during the wait above + players = level.players; + for ( index = 0; index < players.size; index++ ) + { + player = players[index]; + + recordPlayerStats( player, "presentAtEnd", 1 ); + + player closeMenu(); + player closeInGameMenu(); + player notify ( "reset_outcome" ); + player thread [[level.spawnIntermission]](); + player setClientUIVisibilityFlag( "hud_visible", 1 ); + } + //Eckert - Fading out sound + level notify ( "sfade"); + logString( "game ended" ); + + if ( !isDefined( level.skipGameEnd ) || !level.skipGameEnd ) + wait 5.0; + + exitLevel( false ); + +} + +bbPlayerMatchEnd( gameLength, endReasonString, gameOver ) // self == player //checked matches bo3 _globallogic.gsc within reason +{ + 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 ) //checked matches bo3 _globallogic.gsc within reason changed for loop to while loop see github for more info +{ + notifiesDone = false; + while ( !notifiesDone ) + { + players = level.players; + notifiesDone = true; + index = 0; + while ( index < players.size ) + { + if ( !isDefined( players[index].doingNotify ) || !players[index].doingNotify ) + { + index++; + continue; + } + + notifiesDone = false; + 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 = false; + while ( !notifiesDone ) + { + players = level.players; + notifiesDone = true; + index = 0; + while ( index < players.size ) + { + if ( !isDefined( players[index].doingNotify ) || !players[index].doingNotify ) + index++; + continue; + + notifiesDone = false; + index++; + } + wait ( 0.5 ); + } + + level notify ( "round_end_done" ); +} + + +roundEndDOF( time ) //checked matches bo3 _globallogic.gsc within reason +{ + self setDepthOfField( 0, 128, 512, 4000, 6, 1.8 ); +} + + +checkTimeLimit() //checked matches bo3 _globallogic.gsc within reason +{ + 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_zm\_globallogic_utils::getTimeRemaining(); + + // want this accurate to the millisecond + setGameEndTime( getTime() + int(timeLeft) ); + + if ( timeLeft > 0 ) + return; + + [[level.onTimeLimit]](); +} + +allTeamsUnderScoreLimit() //checked matches bo3 _globallogic.gsc within reason +{ + foreach ( team in level.teams ) + { + if ( game["teamScores"][team] >= level.scoreLimit ) + return false; + } + + return true; +} + +checkScoreLimit() //checked matches bo3 _globallogic.gsc within reason +{ + if ( game["state"] != "playing" ) + return false; + + if ( level.scoreLimit <= 0 ) + return false; + + if ( level.teamBased ) + { + if( allTeamsUnderScoreLimit() ) + return false; + } + else + { + if ( !isPlayer( self ) ) + return false; + + if ( self.score < level.scoreLimit ) + return false; + } + + [[level.onScoreLimit]](); +} + + +updateGameTypeDvars() //checked matches bo3 _globallogic.gsc within reason +{ + 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(); + + // make sure we check time limit right when game ends + if ( isdefined( level.startTime ) ) + { + if ( maps\mp\gametypes_zm\_globallogic_utils::getTimeRemaining() < 3000 ) + { + wait .1; + continue; + } + } + wait 1; + } +} + + +removeDisconnectedPlayerFromPlacement() //checked matches bo3 _globallogic.gsc within reason +{ + offset = 0; + numPlayers = level.placement["all"].size; + found = false; + for ( i = 0; i < numPlayers; i++ ) + { + if ( level.placement["all"][i] == self ) + found = true; + + if ( found ) + level.placement["all"][i] = level.placement["all"][ i + 1 ]; + } + if ( !found ) + return; + + level.placement["all"][ numPlayers - 1 ] = undefined; + //assert( level.placement["all"].size == numPlayers - 1 ); + /* + /# + maps\mp\gametypes_zm\_globallogic_utils::assertProperPlacement(); + #/ + */ + updateTeamPlacement(); + + if ( level.teamBased ) + return; + + numPlayers = level.placement["all"].size; + for ( i = 0; i < numPlayers; i++ ) + { + player = level.placement["all"][i]; + player notify( "update_outcome" ); + } + +} + +updatePlacement() //checked matches bo3 _globallogic.gsc within reason +{ + + if ( !level.players.size ) + return; + + level.placement["all"] = []; + for ( index = 0; index < level.players.size; index++ ) + { + if ( isdefined( level.teams[ level.players[index].team ] ) ) + level.placement["all"][level.placement["all"].size] = level.players[index]; + } + + placementAll = level.placement["all"]; + + for ( i = 1; i < placementAll.size; i++ ) + { + player = placementAll[i]; + playerScore = player.score; + } + + level.placement["all"] = placementAll; + /* + /# + maps\mp\gametypes_zm\_globallogic_utils::assertProperPlacement(); + #/ + */ + updateTeamPlacement(); + +} + + +updateTeamPlacement() //checked matches bo3 _globallogic.gsc within reason +{ + foreach( team in level.teams ) + { + placement[team] = []; + } + placement["spectator"] = []; + + if ( !level.teamBased ) + return; + + placementAll = level.placement["all"]; + placementAllSize = placementAll.size; + + for ( i = 0; i < placementAllSize; i++ ) + { + player = placementAll[i]; + team = player.pers["team"]; + + placement[team][ placement[team].size ] = player; + } + + foreach( team in level.teams ) + { + level.placement[team] = placement[team]; + } +} + +getPlacementForPlayer( player ) //checked matches bo3 _globallogic.gsc within reason +{ + updatePlacement(); + + playerRank = -1; + placement = level.placement["all"]; + for ( placementIndex = 0; placementIndex < placement.size; placementIndex++ ) + { + if ( level.placement["all"][placementIndex] == player ) + { + playerRank = (placementIndex + 1); + break; + } + } + + return playerRank; +} + +sortDeadPlayers( team ) //checked matches bo3 _globallogic.gsc within reason +{ + // only need to sort if we are running queued respawn + if ( !level.playerQueuedRespawn ) + return; + + // sort by death time + for ( i = 1; i < level.deadPlayers[team].size; i++ ) + { + player = level.deadPlayers[team][i]; + for ( j = i - 1; j >= 0 && player.deathTime < level.deadPlayers[team][j].deathTime; j-- ) + level.deadPlayers[team][j + 1] = level.deadPlayers[team][j]; + level.deadPlayers[team][j + 1] = player; + } + + for ( i = 0; i < level.deadPlayers[team].size; i++ ) + { + if ( level.deadPlayers[team][i].spawnQueueIndex != i ) + { + level.spawnQueueModified[team] = true; + } + level.deadPlayers[team][i].spawnQueueIndex = i; + } +} + +totalAliveCount() //checked matches bo3 _globallogic.gsc within reason +{ + count = 0; + foreach( team in level.teams ) + { + count += level.aliveCount[team]; + } + return count; +} + +totalPlayerLives() //checked matches bo3 _globallogic.gsc within reason +{ + count = 0; + foreach( team in level.teams ) + { + count += level.playerLives[team]; + } + return count; +} + +totalPlayerCount() //doesn't exist in bo3 _globallogic.gsc leaving in +{ + count = 0; + foreach( team in level.teams ) + { + count += level.playerCount[team]; + } + return count; +} + +initTeamVariables( team ) //checked matches bo3 _globallogic.gsc within reason +{ + + if ( !isdefined( level.aliveCount ) ) + level.aliveCount = []; + + level.aliveCount[team] = 0; + level.lastAliveCount[team] = 0; + + level.everExisted[team] = false; + level.waveDelay[team] = 0; + level.lastWave[team] = 0; + level.wavePlayerSpawnIndex[team] = 0; + + resetTeamVariables( team ); +} + +resetTeamVariables( team ) //checked matches bo3 _globallogic.gsc within reason +{ + 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] = false; +} + +updateTeamStatus() //checked matches bo3 _globallogic.gsc within reason changed at own discretion +{ + // run only once per frame, at the end of the frame. + level notify("updating_team_status"); + level endon("updating_team_status"); + level endon ( "game_ended" ); + waittillframeend; + + wait 0; // Required for Callback_PlayerDisconnect to complete before updateTeamStatus can execute + + if ( game["state"] == "postgame" ) + return; + + resetTimeout(); + + foreach( team in level.teams ) + { + resetTeamVariables( team ); + } + + level.activePlayers = []; + + players = level.players; + for ( i = 0; i < players.size; i++ ) + { + player = players[i]; + + 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_zm\_globallogic_spawn::maySpawn() ) + level.playerLives[team]++; + } + } + } + + totalAlive = totalAliveCount(); + + if ( totalAlive > level.maxPlayerCount ) + level.maxPlayerCount = totalAlive; + + foreach( team in level.teams ) + { + if ( level.aliveCount[team] ) + level.everExisted[team] = true; + + sortDeadPlayers( team ); + } + + level updateGameEvents(); +} + +checkTeamScoreLimitSoon( team ) //checked matches bo3 _globallogic.gsc within reason +{ + //assert( IsDefined( team ) ); + + if ( level.scoreLimit <= 0 ) + return; + + if ( !level.teamBased ) + return; + + // Give the data a minute to converge/settle + if ( maps\mp\gametypes_zm\_globallogic_utils::getTimePassed() < ( 60 * 1000 ) ) + return; + + timeLeft = maps\mp\gametypes_zm\_globallogic_utils::getEstimatedTimeUntilScoreLimit( team ); + + if ( timeLeft < 1 ) + { + level notify( "match_ending_soon", "score" ); + // maps\mp\_gameadvertisement::teamScoreLimitSoon( true ); + } +} + +checkPlayerScoreLimitSoon() //checked matches bo3 _globallogic.gsc within reason +{ + //assert( IsPlayer( self ) ); + + if ( level.scoreLimit <= 0 ) + return; + + if ( level.teamBased ) + return; + + // Give the data a minute to converge/settle + if ( maps\mp\gametypes_zm\_globallogic_utils::getTimePassed() < ( 60 * 1000 ) ) + return; + + timeLeft = maps\mp\gametypes_zm\_globallogic_utils::getEstimatedTimeUntilScoreLimit( undefined ); + + if ( timeLeft < 1 ) + { + level notify( "match_ending_soon", "score" ); + // maps\mp\_gameadvertisement::teamScoreLimitSoon( true ); + } +} + +timeLimitClock() //checked doesn't exist in bo3 _globallogic.gsc leaving in +{ + level endon ( "game_ended" ); + + wait .05; + + clockObject = spawn( "script_origin", (0,0,0) ); + + while ( game["state"] == "playing" ) + { + if ( !level.timerStopped && level.timeLimit ) + { + timeLeft = maps\mp\gametypes_zm\_globallogic_utils::getTimeRemaining() / 1000; + timeLeftInt = int(timeLeft + 0.5); // adding .5 and flooring rounds it. + + 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 <= 30 && timeLeftInt % 2 == 0) || timeLeftInt <= 10 ) + { + level notify ( "match_ending_very_soon", "time" ); + // don't play a tick at exactly 0 seconds, that's when something should be happening! + if ( timeLeftInt == 0 ) + break; + + clockObject playSound( "mpl_ui_timer_countdown" ); + } + + // synchronize to be exactly on the second + if ( timeLeft - floor(timeLeft) >= .05 ) + wait timeLeft - floor(timeLeft); + } + + wait ( 1.0 ); + } +} + +timeLimitClock_Intermission( waitTime ) //checked doesn't exist in bo3 _globallogic.gsc leaving in +{ + setGameEndTime( getTime() + int(waitTime*1000) ); + clockObject = spawn( "script_origin", (0,0,0) ); + + if ( waitTime >= 10.0 ) + wait ( waitTime - 10.0 ); + + for ( ;; ) + { + clockObject playSound( "mpl_ui_timer_countdown" ); + wait ( 1.0 ); + } +} + + +startGame() //checked matches bo3 _globallogic.gsc within reason +{ + thread maps\mp\gametypes_zm\_globallogic_utils::gameTimer(); + level.timerStopped = false; + // RF, disabled this, as it is not required anymore. + //thread maps\mp\gametypes_zm\_spawnlogic::spawnPerFrameUpdate(); + + 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_zm\_globallogic_audio::musicController(); + +// thread maps\mp\gametypes_zm\_gametype_variants::onRoundBegin(); + + recordMatchBegin(); +} + + +waitForPlayers() //checked matches bo3 _globallogic.gsc within reason +{ + /* + if ( level.teamBased ) + while( !level.everExisted[ "axis" ] || !level.everExisted[ "allies" ] ) + wait ( 0.05 ); + else + while ( level.maxPlayerCount < 2 ) + wait ( 0.05 ); + */ +} + +prematchPeriod() //checked matches bo3 _globallogic.gsc within reason +{ + 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 = false; + + for ( index = 0; index < level.players.size; index++ ) + { + level.players[index] freeze_player_controls( false ); + level.players[index] enableWeapons(); + } + +// maps\mp\gametypes_zm\_wager::prematchPeriod(); + + if ( game["state"] != "playing" ) + return; +} + +gracePeriod() //checked matches bo3 _globallogic.gsc within reason +{ + level endon("game_ended"); + + if ( IsDefined( level.gracePeriodFunc ) ) + { + [[ level.gracePeriodFunc ]](); + } + else + { + wait ( level.gracePeriod ); + } + + level notify ( "grace_period_ending" ); + wait ( 0.05 ); + + level.inGracePeriod = false; + + if ( game["state"] != "playing" ) + return; + + if ( level.numLives ) + { + // Players on a team but without a weapon show as dead since they can not get in this round + players = level.players; + + for ( i = 0; i < players.size; i++ ) + { + player = players[i]; + + if ( !player.hasSpawned && player.sessionteam != "spectator" && !isAlive( player ) ) + player.statusicon = "hud_status_dead"; + } + } + + level thread updateTeamStatus(); +} + +watchMatchEndingSoon() //checked matches bo3 _globallogic.gsc within reason +{ + SetDvar( "xblive_matchEndingSoon", 0 ); + level waittill( "match_ending_soon", reason ); + SetDvar( "xblive_matchEndingSoon", 1 ); +} + +assertTeamVariables( ) //checked does not match bo3 _globallogic.gsc did not change +{ + // these are defined in the teamset file + if ( !level.createFX_enabled && !SessionModeIsZombiesGame() ) + { + foreach ( team in level.teams ) + { + /* + Assert( IsDefined( game["strings"][ team + "_win"] ) ); + Assert( IsDefined( game["strings"][ team + "_win_round"] ) ); + Assert( IsDefined( game["strings"][ team + "_mission_accomplished"] ) ); + Assert( IsDefined( game["strings"][ team + "_eliminated"] ) ); + Assert( IsDefined( game["strings"][ team + "_forfeited"] ) ); + Assert( IsDefined( game["strings"][ team + "_name"] ) ); + Assert( IsDefined( game["music"]["spawn_" + team] ) ); + Assert( IsDefined( game["music"]["victory_" + team] ) ); + Assert( IsDefined( game["icons"][team] ) ); + Assert( IsDefined( game["voice"][team] ) ); + */ + } + } +} + +anyTeamHasWaveDelay() //checked matches bo3 _globallogic.gsc within reason +{ + foreach ( team in level.teams ) + { + if ( level.waveDelay[team] ) + return true; + } + + return false; +} + +Callback_StartGameType() //checked matches bo3 _globallogic.gsc within reason +{ + level.prematchPeriod = 0; + level.intermission = false; + + setmatchflag( "cg_drawSpectatorMessages", 1 ); + setmatchflag( "game_ended", 0 ); + + if ( !isDefined( game["gamestarted"] ) ) + { + // defaults if not defined in level script + 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"; + + // if this hits the teams are not setup right + //assert( game["attackers"] != game["defenders"] ); + + // TODO MTEAM - need to update this valid team + foreach( team in level.teams ) + { + if ( !isDefined( game[team] ) ) + game[team] = "pmc"; + } + + 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"]["waiting_to_safespawn"] = &"MP_WAITING_TO_SAFESPAWN"; + 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"; + + //assertTeamVariables(); + + [[level.onPrecacheGameType]](); + + game["gamestarted"] = true; + + game["totalKills"] = 0; + + foreach( team in level.teams ) + { + game["teamScores"][team] = 0; + game["totalKillsTeam"][team] = 0; + } + + if ( !level.splitscreen && !isPreGame() ) + level.prematchPeriod = GetGametypeSetting( "prematchperiod" ); + + if ( GetDvarint( "xblive_clanmatch" ) != 0 ) + { + // TODO MTEAM is this code used anymore? + foreach( team in level.teams ) + { + game["icons"][team] = "composite_emblem_team_axis"; + } + + game["icons"]["allies"] = "composite_emblem_team_allies"; + game["icons"]["axis"] = "composite_emblem_team_axis"; + } + } + + if(!isdefined(game["timepassed"])) + game["timepassed"] = 0; + + if(!isdefined(game["roundsplayed"])) + game["roundsplayed"] = 0; + SetRoundsPlayed( game["roundsplayed"] ); + + if(!isdefined(game["roundwinner"] )) + game["roundwinner"] = []; + + if(!isdefined(game["roundswon"] )) + game["roundswon"] = []; + + if(!isdefined(game["roundswon"]["tie"] )) + game["roundswon"]["tie"] = 0; + + foreach ( team in level.teams ) + { + if(!isdefined(game["roundswon"][team] )) + game["roundswon"][team] = 0; + + level.teamSpawnPoints[team] = []; + level.spawn_point_team_class_names[team] = []; + } + + level.skipVote = false; + level.gameEnded = false; + SetDvar( "g_gameEnded", 0 ); + + level.objIDStart = 0; + level.forcedEnd = false; + level.hostForcedEnd = false; + + level.hardcoreMode = GetGametypeSetting( "hardcoreMode" ); + if ( level.hardcoreMode ) + { + logString( "game mode: hardcore" ); + + //set up friendly fire delay for hardcore + if( !isDefined(level.friendlyFireDelayTime) ) + level.friendlyFireDelayTime = 0; + } + + if ( GetDvar( "scr_max_rank" ) == "" ) + SetDvar( "scr_max_rank", "0" ); + level.rankCap = GetDvarint( "scr_max_rank" ); + + if ( GetDvar( "scr_min_prestige" ) == "" ) + { + SetDvar( "scr_min_prestige", "0" ); + } + level.minPrestige = GetDvarint( "scr_min_prestige" ); + + // this gets set to false when someone takes damage or a gametype-specific event happens. + level.useStartSpawns = true; + + level.roundScoreCarry = GetGametypeSetting( "roundscorecarry" ); + + level.allowHitMarkers = GetGametypeSetting( "allowhitmarkers" ); + level.playerQueuedRespawn = GetGametypeSetting( "playerQueuedRespawn" ); + level.playerForceRespawn = GetGametypeSetting( "playerForceRespawn" ); + + level.perksEnabled = GetGametypeSetting( "perksEnabled" ); + level.disableAttachments = GetGametypeSetting( "disableAttachments" ); + level.disableTacInsert = GetGametypeSetting( "disableTacInsert" ); + level.disableCAC = GetGametypeSetting( "disableCAC" ); + level.disableWeaponDrop = GetGametypeSetting( "disableweapondrop" ); + level.onlyHeadShots = GetGametypeSetting( "onlyHeadshots" ); + + // set to 0 to disable + level.minimumAllowedTeamKills = GetGametypeSetting( "teamKillPunishCount" ) - 1; // punishment starts at the next one + 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.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( "r_reflectionProbeGenerate" ) == "1" ) + level waittill( "eternity" ); + + if( SessionModeIsZombiesGame() ) + { + level.prematchPeriod = 0; + + + //thread maps\mp\gametypes_zm\_persistence::init(); + level.persistentDataInfo = []; + level.maxRecentStats = 10; + level.maxHitLocations = 19; + level.globalShotsFired = 0; + // thread maps\mp\gametypes_zm\_class::init(); + + + // thread maps\mp\gametypes_zm\_menus::init(); + thread maps\mp\gametypes_zm\_hud::init(); + thread maps\mp\gametypes_zm\_serversettings::init(); + thread maps\mp\gametypes_zm\_clientids::init(); + // thread maps\mp\teams\_teams::init(); + thread maps\mp\gametypes_zm\_weaponobjects::init(); + thread maps\mp\gametypes_zm\_scoreboard::init(); + // thread maps\mp\gametypes_zm\_killcam::init(); + thread maps\mp\gametypes_zm\_shellshock::init(); + // thread maps\mp\gametypes_zm\_deathicons::init(); + // thread maps\mp\gametypes_zm\_damagefeedback::init(); + thread maps\mp\gametypes_zm\_spectating::init(); + // thread maps\mp\gametypes_zm\_objpoints::init(); + thread maps\mp\gametypes_zm\_gameobjects::init(); + thread maps\mp\gametypes_zm\_spawnlogic::init(); + // thread maps\mp\gametypes_zm\_battlechatter_mp::init(); + // FIX ME thread maps\mp\killstreaks\_killstreaks::init(); + thread maps\mp\gametypes_zm\_globallogic_audio::init(); + //thread maps\mp\gametypes_zm\_wager::init(); + // thread maps\mp\gametypes_zm\_gametype_variants::init(); + //thread maps\mp\bots\_bot::init(); + //thread maps\mp\_decoy::init(); + } + +// if ( level.teamBased ) +// thread maps\mp\gametypes_zm\_friendicons::init(); + + thread maps\mp\gametypes_zm\_hud_message::init(); + //thread maps\mp\_multi_extracam::init(); + + stringNames = getArrayKeys( game["strings"] ); + for ( index = 0; index < stringNames.size; index++ ) + precacheString( game[ "strings" ][ stringNames[ index ] ] ); + + foreach( team in level.teams ) + { + initTeamVariables( team ); + } + + 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 ); + + // The order the following functions are registered in are the order they will get called +// maps\mp\gametypes_zm\_globallogic_utils::registerPostRoundEvent( maps\mp\gametypes_zm\_killcam::postRoundFinalKillcam ); +// maps\mp\gametypes_zm\_globallogic_utils::registerPostRoundEvent( maps\mp\gametypes_zm\_wager::postRoundSideBet ); + + makeDvarServerInfo( "ui_scorelimit" ); + makeDvarServerInfo( "ui_timelimit" ); + makeDvarServerInfo( "ui_allow_classchange", GetDvar( "ui_allow_classchange" ) ); + + waveDelay = level.waveRespawnDelay; + if ( waveDelay && !isPreGame() ) + { + foreach ( team in level.teams ) + { + level.waveDelay[team] = waveDelay; + level.lastWave[team] = 0; + } + + level thread [[level.waveSpawnTimer]](); + } + + level.inPrematchPeriod = true; + + if ( level.prematchPeriod > 2.0 ) + level.prematchPeriod = level.prematchPeriod + (randomFloat( 4 ) - 2); // live host obfuscation + + if ( level.numLives || anyTeamHasWaveDelay() || level.playerQueuedRespawn ) + level.gracePeriod = 15; + else + level.gracePeriod = 5; + + level.inGracePeriod = true; + + level.roundEndDelay = 5; + level.halftimeRoundEndDelay = 3; + + maps\mp\gametypes_zm\_globallogic_score::updateAllTeamScores(); + + level.killstreaksenabled = 1; + + if ( GetDvar( "scr_game_rankenabled" ) == "" ) + SetDvar( "scr_game_rankenabled", true ); + level.rankEnabled = GetDvarint( "scr_game_rankenabled" ); + + if ( GetDvar( "scr_game_medalsenabled" ) == "" ) + SetDvar( "scr_game_medalsenabled", true ); + level.medalsEnabled = GetDvarint( "scr_game_medalsenabled" ); + + if( level.hardcoreMode && level.rankedMatch && GetDvar( "scr_game_friendlyFireDelay" ) == "" ) + SetDvar( "scr_game_friendlyFireDelay", true ); + level.friendlyFireDelay = GetDvarint( "scr_game_friendlyFireDelay" ); + + // level gametype and features globals should be defaulted before this, and level.onstartgametype should reset them if desired + if(GetDvar("createfx") == "") + { + [[level.onStartGameType]](); + } + + // disable killstreaks for custom game modes + if( GetDvarInt( "custom_killstreak_mode" ) == 1 ) + { + level.killstreaksenabled = 0; + } + + // this must be after onstartgametype for scr_showspawns to work when set at start of game +// /# +// thread maps\mp\gametypes_zm\_dev::init(); +// #/ + /* +/# + PrintLn( "Globallogic Callback_StartGametype() isPregame() = " + isPregame() + "\n" ); +#/ + */ + //level thread maps\mp\gametypes_zm\_killcam::doFinalKillcam(); + + thread startGame(); + level thread updateGameTypeDvars(); + /* +/# + if( GetDvarint( "scr_writeconfigstrings" ) == 1 ) + { + level.skipGameEnd = true; + level.roundLimit = 1; + + // let things settle + wait(1); +// level.forcedEnd = true; + thread forceEnd( false ); +// thread endgame( "tie","" ); + } + if( GetDvarint( "scr_hostmigrationtest" ) == 1 ) + { + thread ForceDebugHostMigration(); + } +#/ + */ +} + + + +ForceDebugHostMigration() //doesn't exist in bo3 _globallogic.gsc leaving in +{ + /* + /# + while (1) + { + maps\mp\gametypes_zm\_hostmigration::waitTillHostMigrationDone(); + wait(60); + starthostmigration(); + maps\mp\gametypes_zm\_hostmigration::waitTillHostMigrationDone(); + //thread forceEnd( false ); + } + #/ + */ +} + + +registerFriendlyFireDelay( dvarString, defaultValue, minValue, maxValue ) //checked matches bo3 _globallogic.gsc within reason +{ + 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() //checked matches bo3 _globallogic.gsc within reason +{ + if ( !isdefined( level.roundSwitch ) || !level.roundSwitch ) + { + return false; + } + if ( !isdefined( level.onRoundSwitch ) ) + { + return false; + } + + //assert( game["roundsplayed"] > 0 ); + + if ( game["roundsplayed"] % level.roundswitch == 0 ) + { + [[level.onRoundSwitch]](); + return true; + } + + return false; +} + + +listenForGameEnd() //checked matches bo3 _globallogic.gsc within reason +{ + self waittill( "host_sucks_end_game" ); + //if ( level.console ) + // endparty(); + level.skipVote = true; + + if ( !level.gameEnded ) + { + level thread maps\mp\gametypes_zm\_globallogic::forceEnd(true); + } +} + + +getKillStreaks( player ) //checked matches bo3 _globallogic.gsc within reason +{ + for ( killstreakNum = 0; killstreakNum < level.maxKillstreaks; killstreakNum++ ) + { + killstreak[ killstreakNum ] = "killstreak_null"; + } + + if ( isPlayer( player ) && !level.oldschool && ( level.disableCAC != 1 ) && + !isdefined( player.pers["isBot"] ) && isdefined(player.killstreak ) ) + { + currentKillstreak = 0; + for ( killstreakNum = 0; killstreakNum < level.maxKillstreaks; killstreakNum++ ) + { + if ( isDefined( player.killstreak[ killstreakNum ] ) ) + { + killstreak[ currentKillstreak ] = player.killstreak[ killstreakNum ]; + currentKillstreak++; + } + } + } + + return killstreak; +} + +updateRankedMatch(winner) //checked matches bo3 _globallogic.gsc within reason +{ + if ( level.rankedMatch ) + { + if ( hostIdledOut() ) + { + level.hostForcedEnd = true; + logString( "host idled out" ); + endLobby(); + } + } + if ( !level.wagerMatch && !SessionModeIsZombiesGame() ) + { + maps\mp\gametypes_zm\_globallogic_score::updateMatchBonusScores( winner ); + maps\mp\gametypes_zm\_globallogic_score::updateWinLossStats( winner ); + } +} + + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_weapons.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_weapons.gsc new file mode 100644 index 0000000..55c93d4 --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_weapons.gsc @@ -0,0 +1,1950 @@ +//checked includes changed to match cerberus output +#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/_sticky_grenade; +#include maps/mp/gametypes_zm/_weaponobjects; +#include maps/mp/gametypes_zm/_weapon_utils; +#include maps/mp/_utility; +#include common_scripts/utility; + +//whole script first checked as mp version then checked againt zm version + +init() //checked changed to match cerberus output +{ + 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( "t6_wpn_tac_insert_world" ); + precachemodel( "t6_wpn_shield_stow_world" ); + precachemodel( "t6_wpn_shield_carry_world" ); + 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() //checked matches cerberus output +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player.usedweapons = 0; + player.lastfiretime = 0; + player.hits = 0; + player scavenger_hud_create(); + player thread onplayerspawned(); + } +} + +onplayerspawned() //checked matches cerberus output +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self.concussionendtime = 0; + self.scavenged = 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() //checked matches cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "turretownerchange", turret ); + self thread watchfortowfire( turret ); + } +} + +watchfortowfire( turret ) //checked matches cerberus output +{ + 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 ) //checked matches cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "turretownerchange" ); + self waittill( "turret_tow_unlink" ); + self relinktoturret( turret ); +} + +watchweaponchange() //checked changed to match cerberus output +{ + 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 ); + } + self.lastweaponchange = 0; + while ( 1 ) + { + previous_weapon = self getcurrentweapon(); + self waittill( "weapon_change", newweapon ); + if ( maydropweapon( newweapon ) ) + { + self.lastdroppableweapon = newweapon; + self.lastweaponchange = getTime(); + } + if ( newweapon != "none" ) + { + if ( !isprimaryweapon( newweapon ) || issidearm( newweapon ) && !isDefined( self.hitsthismag[ newweapon ] ) ) + { + self.hitsthismag[ newweapon ] = weaponclipsize( newweapon ); + } + } + } +} + +watchriotshielduse() //checked changed to match cerberus output +{ +} + +updatelastheldweapontimings( newtime ) //checked matches cerberus output +{ + 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 ) //checked changed to match beta dump +{ + 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; + if ( isDefined( self.weapon_array_grenade ) ) + { + for(i = 0; i < self.weapon_array_grenade.size; i++) + { + self addweaponstat( self.weapon_array_grenade[ i ], "timeUsed", totaltime ); + } + } + if ( isDefined( self.weapon_array_inventory ) ) + { + for(i = 0; i < self.weapon_array_inventory.size; i++) + { + self addweaponstat( self.weapon_array_inventory[ i ], "timeUsed", totaltime ); + } + } + if ( isDefined( self.killstreak ) ) + { + for ( i = 0; i < self.killstreak.size; i++ ) + { + killstreakweapon = level.menureferenceforkillstreak[ self.killstreak[ i ] ]; + if ( isDefined( killstreakweapon ) ) + { + self addweaponstat( killstreakweapon, "timeUsed", totaltime ); + } + } + } + if ( level.rankedmatch && level.perksenabled ) + { + perksindexarray = []; + specialtys = self.specialty; + if ( !isDefined( specialtys ) ) + { + return; + } + if ( !isDefined( self.class ) ) + { + return; + } + if ( isDefined( self.class_num ) ) + { + for ( numspecialties = 0; numspecialties < level.maxspecialties; numspecialties++ ) + { + perk = self getloadoutitem( self.class_num, "specialty" + ( numspecialties + 1 ) ); + if ( perk != 0 ) + { + perksindexarray[ perk ] = 1; + } + } + perkindexarraykeys = getarraykeys( perksindexarray ); + for ( i = 0; i < perkindexarraykeys.size; i++ ) + { + if ( perksindexarray[ perkindexarraykeys[ i ] ] == 1 ) + { + self adddstat( "itemStats", perkindexarraykeys[ i ], "stats", "timeUsed", "statValue", totaltime ); + } + } + } + } +} + +trackweapon() //checked changed to match beta dump +{ + 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; + } + } + else + { + if ( event != "disconnect" && isDefined( self ) ) + { + self maps/mp/_bb::commitweapondata( spawnid, currentweapon, currenttime ); + updateweapontimings( newtime ); + } + return; + } + } +} + +maydropweapon( weapon ) //checked matches cerberus output +{ + 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, sweapon, smeansofdeath ) //checked matches cerberus output dvars taken from beta dump +{ + if ( level.disableweapondrop == 1 ) + { + return; + } + weapon = self.lastdroppableweapon; + if ( isDefined( self.droppeddeathweapon ) ) + { + return; + } + if ( !isDefined( weapon ) ) + { + /* +/# + if ( getDvar( "scr_dropdebug" ) == "1" ) + { + println( "didn't drop weapon: not defined" ); +#/ + } + */ + return; + } + if ( weapon == "none" ) + { + /* +/# + if ( getDvar( "scr_dropdebug" ) == "1" ) + { + println( "didn't drop weapon: weapon == none" ); +#/ + } + */ + return; + } + if ( !self hasweapon( weapon ) ) + { + /* +/# + if ( getDvar( "scr_dropdebug" ) == "1" ) + { + println( "didn't drop weapon: don't have it anymore (" + weapon + ")" ); +#/ + } + */ + return; + } + if ( !self anyammoforweaponmodes( weapon ) ) + { + /* +/# + if ( getDvar( "scr_dropdebug" ) == "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( "scr_dropdebug" ) == "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( "scr_dropdebug" ) == "1" ) + { + println( "dropped weapon: " + weapon ); +#/ + } + */ + droplimitedweapon( weapon, self, item ); + self.droppeddeathweapon = 1; + item itemweaponsetammo( clipammo, stockammo ); + item.owner = self; + item.ownersattacker = attacker; + item.sweapon = sweapon; + item.smeansofdeath = smeansofdeath; + item thread watchpickup(); + item thread deletepickupafterawhile(); +} + +dropweapontoground( weapon ) //checked changed to match cerberus output dvars taken from beta dump +{ + if ( !isDefined( weapon ) ) + { + /* +/# + if ( getDvar( "scr_dropdebug" ) == "1" ) + { + println( "didn't drop weapon: not defined" ); +#/ + } + */ + return; + } + if ( weapon == "none" ) + { + /* +/# + if ( getDvar( "scr_dropdebug" ) == "1" ) + { + println( "didn't drop weapon: weapon == none" ); +#/ + } + */ + return; + } + if ( !self hasweapon( weapon ) ) + { + /* +/# + if ( getDvar( "scr_dropdebug" ) == "1" ) + { + println( "didn't drop weapon: don't have it anymore (" + weapon + ")" ); +#/ + } + */ + return; + } + if ( !self anyammoforweaponmodes( weapon ) ) + { + /* +/# + if ( getDvar( "scr_dropdebug" ) == "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: + break; + } + 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( "scr_dropdebug" ) == "1" ) + { + println( "didn't drop weapon: no ammo" ); +#/ + } + */ + return; + } + stockmax = weaponmaxammo( weapon ); + if ( stockammo > stockmax ) + { + stockammo = stockmax; + } + item = self dropitem( weapon ); + /* +/# + if ( getDvar( "scr_dropdebug" ) == "1" ) + { + println( "dropped weapon: " + weapon ); +#/ + } + */ + droplimitedweapon( weapon, self, item ); + item itemweaponsetammo( clipammo, stockammo ); + item.owner = self; + item thread watchpickup(); + item thread deletepickupafterawhile(); + } +} + +deletepickupafterawhile() //checked matches cerberus output +{ + self endon( "death" ); + wait 60; + if ( !isDefined( self ) ) + { + return; + } + self delete(); +} + +getitemweaponname() //checked matches cerberus output +{ + classname = self.classname; + /* +/# + assert( getsubstr( classname, 0, 7 ) == "weapon_" ); +#/ + */ + weapname = getsubstr( classname, 7 ); + return weapname; +} + +watchpickup() //checked changed to match cerberus output dvar taken from beta dump +{ + self endon( "death" ); + weapname = self getitemweaponname(); + while ( + { + self waittill( "trigger", player, droppeditem ); + if ( isdefined( droppeditem ) ) + { + break; + } + } + /* +/# + if ( getDvar( "scr_dropdebug" ) == "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; + player.tookweaponfrom[ droppedweaponname ] = undefined; + } + droppeditem thread watchpickup(); + if ( isDefined( self.ownersattacker ) && self.ownersattacker == player ) + { + player.tookweaponfrom[ weapname ].previousowner = self.owner; + player.pickedupweaponkills[ weapname ] = 0; + } + else + { + player.tookweaponfrom[ weapname ] = undefined; + player.pickedupweaponkills[ weapname ] = undefined; + } +} + +itemremoveammofromaltmodes() //checked matches cerberus output +{ + origweapname = self getitemweaponname(); + curweapname = weaponaltweaponname( origweapname ); + altindex = 1; + while ( curweapname != "none" && curweapname != origweapname ) + { + self itemweaponsetammo( 0, 0, altindex ); + curweapname = weaponaltweaponname( curweapname ); + altindex++; + } +} + +dropoffhand() //checked partially changed to match cerberus output did not change while loop to for loop see github for more info +{ + grenadetypes = []; + index = 0; + while ( index < grenadetypes.size ) + { + if ( !self hasweapon( grenadetypes[ index ] ) ) + { + index++; + continue; + } + count = self getammocount( grenadetypes[ index ] ); + if ( !count ) + { + index++; + continue; + } + self dropitem( grenadetypes[ index ] ); + index++; + } +} + +watchweaponusage() //checked changed to match cerberus output +{ + 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_mp" ) + { + level.globalcrossbowfired++; + } + if ( curweapon == "crossbow_explosive_mp" ) + { + level.globalcrossbowfired++; + self addweaponstat( curweapon, "shots", 1 ); + self thread begingrenadetracking(); + break; + } + case "mg": + case "pistol": + case "pistol spread": + case "smg": + case "spread": + self trackweaponfire( curweapon ); + level.globalshotsfired++; + break; + case "grenade": + case "rocketlauncher": + self addweaponstat( curweapon, "shots", 1 ); + break; + default: + break; + } + } +} + +updatemagshots( weaponname ) //checked matches cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "updateMagShots_" + weaponname ); + self.hitsthismag[ weaponname ]--; + + wait 0.05; + self.hitsthismag[ weaponname ] = weaponclipsize( weaponname ); +} + +checkhitsthismag( weaponname ) //checked matches cerberus output +{ + 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 ) //checked changed to match cerberus output +{ + 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 ) //checked changed to match cerberus output +{ + switch ( weaponclass( sweapon ) ) + { + case "mg": + case "pistol": + case "rifle": + case "smg": + self.hits++; + break; + case "pistol spread": + case "spread": + self.hits = 1; + break; + default: + break; + } + waittillframeend; + if ( isDefined( self ) && 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() //checked matches cerberus output +{ + 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() //checked matches cerberus output +{ + 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() //checked matches cerberus output +{ + self waittill( "death" ); + arrayremovevalue( level.missileentities, self ); +} + +dropweaponstoground( origin, radius ) //checked changed to match cerberus output +{ + weapons = getdroppedweapons(); + for ( i = 0; i < weapons.size; i++ ) + { + 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" ]; + } + } +} + +dropgrenadestoground( origin, radius ) //checked changed to match cerberus output +{ + grenades = getentarray( "grenade", "classname" ); + for ( i = 0; i < grenades.size; i++ ) + { + if ( distancesquared( origin, grenades[ i ].origin ) < ( radius * radius ) ) + { + grenades[ i ] launch( vectorScale( ( 1, 1, 1 ), 5 ) ); + } + } +} + +watchgrenadecancel() //checked matches cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "grenade_fire" ); + self waittill( "weapon_change", weapon ); + self.throwinggrenade = 0; + self.gotpullbacknotify = 0; +} + +begingrenadetracking() //checked changed to match cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "grenade_throw_cancelled" ); + 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/_utility::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() //checked matches cerberus output +{ +} + +checkstucktoplayer( deleteonteamchange, awardscoreevent, weaponname ) //checked matches cerberus output +{ + self endon( "death" ); + self waittill( "stuck_to_player", player ); + if ( isDefined( player ) ) + { + if ( deleteonteamchange ) + { + self thread stucktoplayerteamchange( player ); + } + if ( awardscoreevent && isDefined( self.originalowner ) ) + { + } + self.stucktoplayer = player; + } +} + +checkhatchetbounce() //checked matches cerberus output +{ + self endon( "stuck_to_player" ); + self endon( "death" ); + self waittill( "grenade_bounce" ); + self.bounced = 1; +} + +stucktoplayerteamchange( player ) //checked matches cerberus output +{ + 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() //checked matches cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + self waittill_any( "grenade_fire", "weapon_change" ); + self.throwinggrenade = 0; +} + +watchforthrowbacks() //checked changed to match cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "grenade_fire", grenade, weapname ); + if ( self.gotpullbacknotify ) + { + self.gotpullbacknotify = 0; + continue; + } + if ( !issubstr( weapname, "frag_" ) ) + { + continue; + } + grenade.threwback = 1; + grenade.originalowner = self; + } +} + +registergrenadelauncherduddvar( dvarstring, defaultvalue, minvalue, maxvalue ) //checked changed to match cerberus output +{ + 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 ) //checked changed to match cerberus output +{ + 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 ) //checked changed to match cerberus output +{ + 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 ) //checked changed to match cerberus output +{ + 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() //checked matches cerberus output +{ + self endon( "spawned_player" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "grenade_fire", grenade, weapname ); + grenade turngrenadeintoadud( weapname, 1, self ); + } +} + +watchforgrenadelauncherduds() //checked matches cerberus output +{ + 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 ) //checked partially changed to match cerberus output did not use continue in for loop and foreach see github for more info +{ + ents = []; + if ( !isDefined( dolos ) ) + { + dolos = 0; + } + if ( !isDefined( startradius ) ) + { + startradius = 0; + } + players = level.players; + for ( i = 0; i < players.size; i++ ) + { + if ( !isalive( players[ i ] ) || players[ i ].sessionstate != "playing" ) + { + } + 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; + } + } + } + grenades = getentarray( "grenade", "classname" ); + for ( i = 0; i < grenades.size; i++ ) + { + 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; + } + } + destructibles = getentarray( "destructible", "targetname" ); + for ( i = 0; i < destructibles.size; i++ ) + { + 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; + } + } + destructables = getentarray( "destructable", "targetname" ); + for ( i = 0; i < destructables.size; i++ ) + { + 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; + } + } + return ents; +} + +weapondamagetracepassed( from, to, startradius, ignore ) //checked matches cerberus output +{ + trace = weapondamagetrace( from, to, startradius, ignore ); + return trace[ "fraction" ] == 1; +} + +weapondamagetrace( from, to, startradius, ignore ) //checked changed to match cerberus output +{ + 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( "scr_damage_debug" ) != 0 ) + { + if ( trace[ "fraction" ] == 1 ) + { + thread debugline( midpos, to, ( 1, 1, 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 ) //checked does not match cerberus output matches beta dump +{ + 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, 0 ), ( 0, 0, 0 ), "mod_explosive", "", "" ); + } +} + +debugline( a, b, color ) //checked changed to match cerberus output +{ + /* +/# + for ( i = 0; i < 600; i++ ) + { + line( a, b, color ); + wait 0.05; +#/ + } + */ +} + +onweapondamage( eattacker, einflictor, sweapon, meansofdeath, damage ) //checked matches cerberus output +{ + 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 ) //checked matches cerberus output +{ + 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 ) //checked matches cerberus output +{ + self endon( "delete" ); + owner waittill( "death" ); + self delete(); +} + +monitor_dog_special_grenades() //checked matches cerberus output +{ +} + +isprimaryweapon( weaponname ) //checked matches cerberus output +{ + return isDefined( level.primary_weapon_array[ weaponname ] ); +} + +issidearm( weaponname ) //checked matches cerberus output +{ + return isDefined( level.side_arm_array[ weaponname ] ); +} + +isinventory( weaponname ) //checked matches cerberus output +{ + return isDefined( level.inventory_array[ weaponname ] ); +} + +isgrenade( weaponname ) //checked matches cerberus output +{ + return isDefined( level.grenade_array[ weaponname ] ); +} + +isexplosivebulletweapon( weaponname ) //checked changed to match cerberus output +{ + 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 ) //checked changed to match cerberus output +{ + 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() //checked partially changed to match cerberus output did not use for loop see github for more info +{ + 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: + break; + } + if ( isprimaryweapon( weaponslist[ idx ] ) ) + { + self.weapon_array_primary[ self.weapon_array_primary.size ] = weaponslist[ idx ]; + idx++; + continue; + } + if ( issidearm( weaponslist[ idx ] ) ) + { + self.weapon_array_sidearm[ self.weapon_array_sidearm.size ] = weaponslist[ idx ]; + idx++; + continue; + } + if ( isgrenade( weaponslist[ idx ] ) ) + { + self.weapon_array_grenade[ self.weapon_array_grenade.size ] = weaponslist[ idx ]; + idx++; + continue; + } + if ( isinventory( weaponslist[ idx ] ) ) + { + self.weapon_array_inventory[ self.weapon_array_inventory.size ] = weaponslist[ idx ]; + idx++; + continue; + } + 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() //checked matches cerberus output +{ + detach_all_weapons(); + stow_on_back(); + stow_on_hip(); +} + +detachcarryobjectmodel() //checked matches cerberus output +{ + 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() //checked matches cerberus output +{ + 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 ) //checked matches cerberus output +{ + 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 ) //checked partially changed to match cerberus output did not use for loop see github for more info +{ + current = self getcurrentweapon(); + currentalt = self getcurrentweaponaltweapon(); + 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; + } + if ( non_stowed_weapon( current ) || self.hasriotshield ) + { + return; + } + if ( current != "none" ) + { + 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, "_" ); + for ( i = 0; i < index_weapon_tok.size; i++ ) + { + if ( !issubstr( current, index_weapon_tok[ i ] ) || index_weapon_tok.size != current_tok.size ) + { + i = 0; + break; + } + } + if ( i == index_weapon_tok.size ) + { + continue; + } + } + 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 ); + } + 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() //checked partially changed to match cerberus output did not use for loop see github for more info +{ + 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; + } + if ( !self getweaponammostock( self.weapon_array_inventory[ idx ] ) ) + { + idx++; + continue; + } + 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 ) //checked matches cerberus output +{ + 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 ) //checked matches cerberus output +{ + return int( weapons_get_dvar( dvar, def ) ); +} + +weapons_get_dvar( dvar, def ) //checked matches cerberus output +{ + if ( getDvar( dvar ) != "" ) + { + return getDvarFloat( dvar ); + } + else + { + setdvar( dvar, def ); + return def; + } +} + +player_is_driver() //checked matches cerberus output +{ + 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() //checked matches cerberus output +{ + /* +/# + 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 ) //checked matches cerberus output +{ + if ( isDefined( level.givecustomloadout ) ) + { + return "weapon_null_mp"; + } + /* +/# + assert( isDefined( self.class_num ) ); +#/ + */ + if ( isDefined( self.class_num ) ) + { + index = self maps/mp/gametypes_zm/_class::getloadoutitemfromddlstats( self.class_num, stat ); + 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 ) //checked matches cerberus output +{ + count = 0; + if ( isDefined( level.givecustomloadout ) ) + { + return 0; + } + /* +/# + assert( isDefined( self.class_num ) ); +#/ + */ + if ( isDefined( self.class_num ) ) + { + count = self maps/mp/gametypes_zm/_class::getloadoutitemfromddlstats( self.class_num, stat ); + } + return count; +} + +scavenger_think() //checked partially changed to match cerberus output did not use for loops see github for more info +{ + 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" ); + offhand_weapons_and_alts = array_reverse( offhand_weapons_and_alts ); + 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; + 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 ) ) + { + i++; + continue; + } + switch ( weapon ) + { + case "satchel_charge_mp": + if ( player maps/mp/gametypes_zm/_weaponobjects::anyobjectsinworld( weapon ) ) + { + break; + } + case "bouncingbetty_mp": + case "claymore_mp": + case "frag_grenade_mp": + case "hatchet_mp": + case "sticky_grenade_mp": + if ( isDefined( player.grenadetypeprimarycount ) && player.grenadetypeprimarycount < 1 ) + { + break; + } + 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; + } + 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.scavenged = 1; + player thread maps/mp/_challenges::scavengedgrenade(); + } + break; + } + i++; + } + i = 0; + while ( i < primary_weapons.size ) + { + weapon = primary_weapons[ i ]; + if ( ishackweapon( weapon ) || weapon == "kniferang_mp" ) + { + i++; + continue; + } + stock = player getweaponammostock( weapon ); + start = player getfractionstartammo( weapon ); + clip = weaponclipsize( weapon ); + clip *= getdvarfloatdefault( "scavenger_clip_multiplier", 1 ); + clip = int( clip ); + maxammo = weaponmaxammo( weapon ); + if ( stock < ( maxammo - clip ) ) + { + ammo = stock + clip; + player setweaponammostock( weapon, ammo ); + player.scavenged = 1; + exit_early = 1; + i++; + continue; + } + player setweaponammostock( weapon, maxammo ); + player.scavenged = 1; + exit_early = 1; + i++; + } +} + +scavenger_hud_create() //checked matches cerberus output +{ + if ( level.wagermatch ) + { + return; + } + self.scavenger_icon = newclienthudelem( self ); + self.scavenger_icon.horzalign = "center"; + self.scavenger_icon.vertalign = "middle"; + self.scavenger_icon.alpha = 0; + width = 48; + height = 24; + if ( level.splitscreen ) + { + width = int( width * 0.5 ); + height = int( height * 0.5 ); + } + self.scavenger_icon.x = ( width * -1 ) / 2; + self.scavenger_icon.y = 16; + self.scavenger_icon setshader( "hud_scavenger_pickup", width, height ); +} + +dropscavengerfordeath( attacker ) //checked matches cerberus output +{ + 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 if ( isplayer( attacker ) && attacker hasperk( "specialty_scavenger" ) ) + { + item = self dropscavengeritem( "scavenger_item_mp" ); + } + else + { + return; + } + item thread scavenger_think(); +} + +addlimitedweapon( weapon_name, owner, num_drops ) //checked matches cerberus output +{ + limited_info = spawnstruct(); + limited_info.weapon = weapon_name; + limited_info.drops = num_drops; + owner.limited_info = limited_info; +} + +shoulddroplimitedweapon( weapon_name, owner ) //checked matches cerberus output +{ + 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 ) //checked matches cerberus output +{ + 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 ) //checked matches cerberus output +{ + self endon( "death" ); + self waittill( "trigger", player, item ); + if ( !isDefined( item ) ) + { + return; + } + player.limited_info = limited_info; +} + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_zm_gametype.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_zm_gametype.gsc new file mode 100644 index 0000000..40b63af --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/gametypes_zm/_zm_gametype.gsc @@ -0,0 +1,1997 @@ +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_game_module; +#include maps/mp/zombies/_zm_pers_upgrades_functions; +#include maps/mp/zombies/_zm_blockers; +#include maps/mp/gametypes_zm/_spawning; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/zombies/_zm_audio_announcer; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/gametypes_zm/_globallogic_ui; +#include maps/mp/gametypes_zm/_hud_message; +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/gametypes_zm/_globallogic_defaults; +#include maps/mp/gametypes_zm/_globallogic_spawn; +#include maps/mp/gametypes_zm/_gameobjects; +#include maps/mp/gametypes_zm/_weapons; +#include maps/mp/gametypes_zm/_callbacksetup; +#include maps/mp/gametypes_zm/_globallogic; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/_utility; + +main() //checked matches cerberus output +{ + maps/mp/gametypes_zm/_globallogic::init(); + maps/mp/gametypes_zm/_callbacksetup::setupcallbacks(); + globallogic_setupdefault_zombiecallbacks(); + menu_init(); + registerroundlimit( 1, 1 ); + registertimelimit( 0, 0 ); + registerscorelimit( 0, 0 ); + registerroundwinlimit( 0, 0 ); + registernumlives( 1, 1 ); + maps/mp/gametypes_zm/_weapons::registergrenadelauncherduddvar( level.gametype, 10, 0, 1440 ); + maps/mp/gametypes_zm/_weapons::registerthrowngrenadeduddvar( level.gametype, 0, 0, 1440 ); + maps/mp/gametypes_zm/_weapons::registerkillstreakdelay( level.gametype, 0, 0, 1440 ); + maps/mp/gametypes_zm/_globallogic::registerfriendlyfiredelay( level.gametype, 15, 0, 1440 ); + level.takelivesondeath = 1; + level.teambased = 1; + level.disableprematchmessages = 1; + level.disablemomentum = 1; + level.overrideteamscore = 0; + level.overrideplayerscore = 0; + level.displayhalftimetext = 0; + level.displayroundendtext = 0; + level.allowannouncer = 0; + level.endgameonscorelimit = 0; + level.endgameontimelimit = 0; + level.resetplayerscoreeveryround = 1; + level.doprematch = 0; + level.nopersistence = 1; + level.scoreroundbased = 0; + level.forceautoassign = 1; + level.dontshowendreason = 1; + level.forceallallies = 0; + level.allow_teamchange = 0; + setdvar( "scr_disable_team_selection", 1 ); + makedvarserverinfo( "scr_disable_team_selection", 1 ); + setmatchflag( "hud_zombie", 1 ); + setdvar( "scr_disable_weapondrop", 1 ); + setdvar( "scr_xpscale", 0 ); + level.onstartgametype = ::onstartgametype; + level.onspawnplayer = ::blank; + level.onspawnplayerunified = ::onspawnplayerunified; + level.onroundendgame = ::onroundendgame; + level.mayspawn = ::mayspawn; + set_game_var( "ZM_roundLimit", 1 ); + set_game_var( "ZM_scoreLimit", 1 ); + set_game_var( "_team1_num", 0 ); + set_game_var( "_team2_num", 0 ); + map_name = level.script; + mode = getDvar( "ui_gametype" ); + if ( !isDefined( mode ) && isDefined( level.default_game_mode ) || mode == "" && isDefined( level.default_game_mode ) ) + { + mode = level.default_game_mode; + } + set_gamemode_var_once( "mode", mode ); + set_game_var_once( "side_selection", 1 ); + location = getDvar( "ui_zm_mapstartlocation" ); + if ( location == "" && isDefined( level.default_start_location ) ) + { + location = level.default_start_location; + } + set_gamemode_var_once( "location", location ); + set_gamemode_var_once( "randomize_mode", getDvarInt( "zm_rand_mode" ) ); + set_gamemode_var_once( "randomize_location", getDvarInt( "zm_rand_loc" ) ); + set_gamemode_var_once( "team_1_score", 0 ); + set_gamemode_var_once( "team_2_score", 0 ); + set_gamemode_var_once( "current_round", 0 ); + set_gamemode_var_once( "rules_read", 0 ); + set_game_var_once( "switchedsides", 0 ); + gametype = getDvar( "ui_gametype" ); + game[ "dialog" ][ "gametype" ] = gametype + "_start"; + game[ "dialog" ][ "gametype_hardcore" ] = gametype + "_start"; + game[ "dialog" ][ "offense_obj" ] = "generic_boost"; + game[ "dialog" ][ "defense_obj" ] = "generic_boost"; + set_gamemode_var( "pre_init_zombie_spawn_func", undefined ); + set_gamemode_var( "post_init_zombie_spawn_func", undefined ); + set_gamemode_var( "match_end_notify", undefined ); + set_gamemode_var( "match_end_func", undefined ); + setscoreboardcolumns( "score", "kills", "downs", "revives", "headshots" ); + onplayerconnect_callback( ::onplayerconnect_check_for_hotjoin ); +} + +game_objects_allowed( mode, location ) //checked partially changed to match cerberus output changed at own discretion +{ + allowed[ 0 ] = mode; + entities = getentarray(); + i = 0; + while ( i < entities.size ) + { + if ( isDefined( entities[ i ].script_gameobjectname ) ) + { + isallowed = maps/mp/gametypes_zm/_gameobjects::entity_is_allowed( entities[ i ], allowed ); + isvalidlocation = maps/mp/gametypes_zm/_gameobjects::location_is_allowed( entities[ i ], location ); + if ( !isallowed || !isvalidlocation && !is_classic() ) + { + if ( isDefined( entities[ i ].spawnflags ) && entities[ i ].spawnflags == 1 ) + { + if ( isDefined( entities[ i ].classname ) && entities[ i ].classname != "trigger_multiple" ) + { + entities[ i ] connectpaths(); + } + } + entities[ i ] delete(); + i++; + continue; + } + if ( isDefined( entities[ i ].script_vector ) ) + { + entities[ i ] moveto( entities[ i ].origin + entities[ i ].script_vector, 0.05 ); + entities[ i ] waittill( "movedone" ); + if ( isDefined( entities[ i ].spawnflags ) && entities[ i ].spawnflags == 1 ) + { + entities[ i ] disconnectpaths(); + } + i++; + continue; + } + if ( isDefined( entities[ i ].spawnflags ) && entities[ i ].spawnflags == 1 ) + { + if ( isDefined( entities[ i ].classname ) && entities[ i ].classname != "trigger_multiple" ) + { + entities[ i ] connectpaths(); + } + } + } + i++; + } +} + +post_init_gametype() //checked matches cerberus output +{ + if ( isDefined( level.gamemode_map_postinit ) ) + { + if ( isDefined( level.gamemode_map_postinit[ level.scr_zm_ui_gametype ] ) ) + { + [[ level.gamemode_map_postinit[ level.scr_zm_ui_gametype ] ]](); + } + } +} + +post_gametype_main( mode ) //checked matches cerberus output +{ + set_game_var( "ZM_roundWinLimit", get_game_var( "ZM_roundLimit" ) * 0.5 ); + level.roundlimit = get_game_var( "ZM_roundLimit" ); + if ( isDefined( level.gamemode_map_preinit ) ) + { + if ( isDefined( level.gamemode_map_preinit[ mode ] ) ) + { + [[ level.gamemode_map_preinit[ mode ] ]](); + } + } +} + +globallogic_setupdefault_zombiecallbacks() //checked matches cerberus output +{ + level.spawnplayer = maps/mp/gametypes_zm/_globallogic_spawn::spawnplayer; + level.spawnplayerprediction = maps/mp/gametypes_zm/_globallogic_spawn::spawnplayerprediction; + level.spawnclient = maps/mp/gametypes_zm/_globallogic_spawn::spawnclient; + level.spawnspectator = maps/mp/gametypes_zm/_globallogic_spawn::spawnspectator; + level.spawnintermission = maps/mp/gametypes_zm/_globallogic_spawn::spawnintermission; + level.onplayerscore = ::blank; + level.onteamscore = ::blank; + + //doesn't exist in any dump or any other script no idea what its trying to override to + level.wavespawntimer = maps/mp/gametypes_zm/_globallogic::wavespawntimer; + level.onspawnplayer = ::blank; + level.onspawnplayerunified = ::blank; + level.onspawnspectator = ::onspawnspectator; + level.onspawnintermission = ::onspawnintermission; + level.onrespawndelay = ::blank; + level.onforfeit = ::blank; + level.ontimelimit = ::blank; + level.onscorelimit = ::blank; + level.ondeadevent = ::ondeadevent; + level.ononeleftevent = ::blank; + level.giveteamscore = ::blank; + level.giveplayerscore = ::blank; + level.gettimelimit = maps/mp/gametypes_zm/_globallogic_defaults::default_gettimelimit; + level.getteamkillpenalty = ::blank; + level.getteamkillscore = ::blank; + level.iskillboosting = ::blank; + level._setteamscore = maps/mp/gametypes_zm/_globallogic_score::_setteamscore; + level._setplayerscore = ::blank; + level._getteamscore = ::blank; + level._getplayerscore = ::blank; + level.onprecachegametype = ::blank; + level.onstartgametype = ::blank; + level.onplayerconnect = ::blank; + level.onplayerdisconnect = ::onplayerdisconnect; + level.onplayerdamage = ::blank; + level.onplayerkilled = ::blank; + level.onplayerkilledextraunthreadedcbs = []; + level.onteamoutcomenotify = maps/mp/gametypes_zm/_hud_message::teamoutcomenotifyzombie; + level.onoutcomenotify = ::blank; + level.onteamwageroutcomenotify = ::blank; + level.onwageroutcomenotify = ::blank; + level.onendgame = ::onendgame; + level.onroundendgame = ::blank; + level.onmedalawarded = ::blank; + level.autoassign = maps/mp/gametypes_zm/_globallogic_ui::menuautoassign; + level.spectator = maps/mp/gametypes_zm/_globallogic_ui::menuspectator; + level.class = maps/mp/gametypes_zm/_globallogic_ui::menuclass; + level.allies = ::menuallieszombies; + level.teammenu = maps/mp/gametypes_zm/_globallogic_ui::menuteam; + level.callbackactorkilled = ::blank; + level.callbackvehicledamage = ::blank; +} + +setup_standard_objects( location ) //checked partially used cerberus output +{ + structs = getstructarray( "game_mode_object" ); + i = 0; + while ( i < structs.size ) + { + if ( isdefined( structs[ i ].script_noteworthy ) && structs[ i ].script_noteworthy != location ) + { + i++; + continue; + } + if ( isdefined( structs[ i ].script_string ) ) + { + keep = 0; + tokens = strtok( structs[ i ].script_string, " " ); + foreach ( token in tokens ) + { + if ( token == level.scr_zm_ui_gametype && token != "zstandard" ) + { + keep = 1; + continue; + } + else if ( token == "zstandard" ) + { + keep = 1; + } + } + if ( !keep ) + { + i++; + continue; + } + } + barricade = spawn( "script_model", structs[ i ].origin ); + barricade.angles = structs[ i ].angles; + barricade setmodel( structs[ i ].script_parameters ); + i++; + } + objects = getentarray(); + i = 0; + while ( i < objects.size ) + { + if ( !objects[ i ] is_survival_object() ) + { + i++; + continue; + } + if ( isdefined( objects[ i ].spawnflags ) && objects[ i ].spawnflags == 1 && objects[ i ].classname != "trigger_multiple" ) + { + objects[ i ] connectpaths(); + } + objects[ i ] delete(); + i++; + } + if ( isdefined( level._classic_setup_func ) ) + { + [[ level._classic_setup_func ]](); + } +} + + +is_survival_object() //checked changed to cerberus output +{ + if ( !isdefined( self.script_parameters ) ) + { + return 0; + } + tokens = strtok( self.script_parameters, " " ); + remove = 0; + foreach ( token in tokens ) + { + if ( token == "survival_remove" ) + { + remove = 1; + } + } + return remove; +} + +game_module_player_damage_callback( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime ) //checked partially changed output to cerberus output +{ + self.last_damage_from_zombie_or_player = 0; + if ( isDefined( eattacker ) ) + { + if ( isplayer( eattacker ) && eattacker == self ) + { + return; + } + if ( isDefined( eattacker.is_zombie ) || eattacker.is_zombie && isplayer( eattacker ) ) + { + self.last_damage_from_zombie_or_player = 1; + } + } + if ( is_true( self._being_shellshocked ) || self maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + return; + } + if ( isplayer( eattacker ) && isDefined( eattacker._encounters_team ) && eattacker._encounters_team != self._encounters_team ) + { + if ( is_true( self.hasriotshield ) && isDefined( vdir ) ) + { + if ( is_true( self.hasriotshieldequipped ) ) + { + if ( self maps/mp/zombies/_zm::player_shield_facing_attacker( vdir, 0.2 ) && isDefined( self.player_shield_apply_damage ) ) + { + return; + } + } + else if ( !isdefined( self.riotshieldentity ) ) + { + if ( !self maps/mp/zombies/_zm::player_shield_facing_attacker( vdir, -0.2 ) && isdefined( self.player_shield_apply_damage ) ) + { + return; + } + } + } + if ( isDefined( level._game_module_player_damage_grief_callback ) ) + { + self [[ level._game_module_player_damage_grief_callback ]]( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime ); + } + if ( isDefined( level._effect[ "butterflies" ] ) ) + { + if ( isDefined( sweapon ) && weapontype( sweapon ) == "grenade" ) + { + playfx( level._effect[ "butterflies" ], self.origin + vectorScale( ( 1, 1, 1 ), 40 ) ); + } + else + { + playfx( level._effect[ "butterflies" ], vpoint, vdir ); + } + } + self thread do_game_mode_shellshock(); + self playsound( "zmb_player_hit_ding" ); + } +} + +do_game_mode_shellshock() //checked matched cerberus output +{ + self endon( "disconnect" ); + self._being_shellshocked = 1; + self shellshock( "grief_stab_zm", 0.75 ); + wait 0.75; + self._being_shellshocked = 0; +} + +add_map_gamemode( mode, preinit_func, precache_func, main_func ) //checked matches cerberus output +{ + if ( !isDefined( level.gamemode_map_location_init ) ) + { + level.gamemode_map_location_init = []; + } + if ( !isDefined( level.gamemode_map_location_main ) ) + { + level.gamemode_map_location_main = []; + } + if ( !isDefined( level.gamemode_map_preinit ) ) + { + level.gamemode_map_preinit = []; + } + if ( !isDefined( level.gamemode_map_postinit ) ) + { + level.gamemode_map_postinit = []; + } + if ( !isDefined( level.gamemode_map_precache ) ) + { + level.gamemode_map_precache = []; + } + if ( !isDefined( level.gamemode_map_main ) ) + { + level.gamemode_map_main = []; + } + level.gamemode_map_preinit[ mode ] = preinit_func; + level.gamemode_map_main[ mode ] = main_func; + level.gamemode_map_precache[ mode ] = precache_func; + level.gamemode_map_location_precache[ mode ] = []; + level.gamemode_map_location_main[ mode ] = []; +} + +add_map_location_gamemode( mode, location, precache_func, main_func ) //checked matches cerberus output +{ + if ( !isDefined( level.gamemode_map_location_precache[ mode ] ) ) + { + /* +/# + println( "*** ERROR : " + mode + " has not been added to the map using add_map_gamemode." ); +#/ + */ + return; + } + level.gamemode_map_location_precache[ mode ][ location ] = precache_func; + level.gamemode_map_location_main[ mode ][ location ] = main_func; +} + +rungametypeprecache( gamemode ) //checked matches cerberus output +{ + if ( !isDefined( level.gamemode_map_location_main ) || !isDefined( level.gamemode_map_location_main[ gamemode ] ) ) + { + return; + } + if ( isDefined( level.gamemode_map_precache ) ) + { + if ( isDefined( level.gamemode_map_precache[ gamemode ] ) ) + { + [[ level.gamemode_map_precache[ gamemode ] ]](); + } + } + if ( isDefined( level.gamemode_map_location_precache ) ) + { + if ( isDefined( level.gamemode_map_location_precache[ gamemode ] ) ) + { + loc = getDvar( "ui_zm_mapstartlocation" ); + if ( loc == "" && isDefined( level.default_start_location ) ) + { + loc = level.default_start_location; + } + if ( isDefined( level.gamemode_map_location_precache[ gamemode ][ loc ] ) ) + { + [[ level.gamemode_map_location_precache[ gamemode ][ loc ] ]](); + } + } + } + if ( isDefined( level.precachecustomcharacters ) ) + { + self [[ level.precachecustomcharacters ]](); + } +} + +rungametypemain( gamemode, mode_main_func, use_round_logic ) //checked matches cerberus output +{ + if ( !isDefined( level.gamemode_map_location_main ) || !isDefined( level.gamemode_map_location_main[ gamemode ] ) ) + { + return; + } + level thread game_objects_allowed( get_gamemode_var( "mode" ), get_gamemode_var( "location" ) ); + if ( isDefined( level.gamemode_map_main ) ) + { + if ( isDefined( level.gamemode_map_main[ gamemode ] ) ) + { + level thread [[ level.gamemode_map_main[ gamemode ] ]](); + } + } + if ( isDefined( level.gamemode_map_location_main ) ) + { + if ( isDefined( level.gamemode_map_location_main[ gamemode ] ) ) + { + loc = getDvar( "ui_zm_mapstartlocation" ); + if ( loc == "" && isDefined( level.default_start_location ) ) + { + loc = level.default_start_location; + } + if ( isDefined( level.gamemode_map_location_main[ gamemode ][ loc ] ) ) + { + level thread [[ level.gamemode_map_location_main[ gamemode ][ loc ] ]](); + } + } + } + if ( isDefined( mode_main_func ) ) + { + if ( is_true( use_round_logic ) ) + { + level thread round_logic( mode_main_func ); + } + else + { + level thread non_round_logic( mode_main_func ); + } + } + level thread game_end_func(); +} + + +round_logic( mode_logic_func ) //checked matches cerberus output +{ + level.skit_vox_override = 1; + if ( isDefined( level.flag[ "start_zombie_round_logic" ] ) ) + { + flag_wait( "start_zombie_round_logic" ); + } + flag_wait( "start_encounters_match_logic" ); + if ( !isDefined( game[ "gamemode_match" ][ "rounds" ] ) ) + { + game[ "gamemode_match" ][ "rounds" ] = []; + } + set_gamemode_var_once( "current_round", 0 ); + set_gamemode_var_once( "team_1_score", 0 ); + set_gamemode_var_once( "team_2_score", 0 ); + if ( is_true( is_encounter() ) ) + { + [[ level._setteamscore ]]( "allies", get_gamemode_var( "team_2_score" ) ); + [[ level._setteamscore ]]( "axis", get_gamemode_var( "team_1_score" ) ); + } + flag_set( "pregame" ); + waittillframeend; + level.gameended = 0; + cur_round = get_gamemode_var( "current_round" ); + set_gamemode_var( "current_round", cur_round + 1 ); + game[ "gamemode_match" ][ "rounds" ][ cur_round ] = spawnstruct(); + game[ "gamemode_match" ][ "rounds" ][ cur_round ].mode = getDvar( "ui_gametype" ); + level thread [[ mode_logic_func ]](); + flag_wait( "start_encounters_match_logic" ); + level.gamestarttime = getTime(); + level.gamelengthtime = undefined; + level notify( "clear_hud_elems" ); + level waittill( "game_module_ended", winner ); + game[ "gamemode_match" ][ "rounds" ][ cur_round ].winner = winner; + level thread kill_all_zombies(); + level.gameendtime = getTime(); + level.gamelengthtime = level.gameendtime - level.gamestarttime; + level.gameended = 1; + if ( winner == "A" ) + { + score = get_gamemode_var( "team_1_score" ); + set_gamemode_var( "team_1_score", score + 1 ); + } + else + { + score = get_gamemode_var( "team_2_score" ); + set_gamemode_var( "team_2_score", score + 1 ); + } + if ( is_true( is_encounter() ) ) + { + [[ level._setteamscore ]]( "allies", get_gamemode_var( "team_2_score" ) ); + [[ level._setteamscore ]]( "axis", get_gamemode_var( "team_1_score" ) ); + if ( get_gamemode_var( "team_1_score" ) == get_gamemode_var( "team_2_score" ) ) + { + level thread maps/mp/zombies/_zm_audio::zmbvoxcrowdonteam( "win" ); + level thread maps/mp/zombies/_zm_audio_announcer::announceroundwinner( "tied" ); + } + else + { + level thread maps/mp/zombies/_zm_audio::zmbvoxcrowdonteam( "win", winner, "lose" ); + level thread maps/mp/zombies/_zm_audio_announcer::announceroundwinner( winner ); + } + } + level thread delete_corpses(); + level delay_thread( 5, ::revive_laststand_players ); + level notify( "clear_hud_elems" ); + while ( startnextzmround( winner ) ) + { + level clientnotify( "gme" ); + while ( 1 ) + { + wait 1; + } + } + level.match_is_ending = 1; + if ( is_true( is_encounter() ) ) + { + matchwonteam = ""; + if ( get_gamemode_var( "team_1_score" ) > get_gamemode_var( "team_2_score" ) ) + { + matchwonteam = "A"; + } + else + { + matchwonteam = "B"; + } + level thread maps/mp/zombies/_zm_audio::zmbvoxcrowdonteam( "win", matchwonteam, "lose" ); + level thread maps/mp/zombies/_zm_audio_announcer::announcematchwinner( matchwonteam ); + level create_final_score(); + track_encounters_win_stats( matchwonteam ); + } + maps/mp/zombies/_zm::intermission(); + level.can_revive_game_module = undefined; + level notify( "end_game" ); +} + +end_rounds_early( winner ) //checked matches cerberus output +{ + level.forcedend = 1; + cur_round = get_gamemode_var( "current_round" ); + set_gamemode_var( "ZM_roundLimit", cur_round ); + if ( isDefined( winner ) ) + { + level notify( "game_module_ended" ); + } + else + { + level notify( "end_game" ); + } +} + + +checkzmroundswitch() //checked matches cerberus output +{ + if ( !isDefined( level.zm_roundswitch ) || !level.zm_roundswitch ) + { + return 0; + } + + return 1; + return 0; +} + +create_hud_scoreboard( duration, fade ) //checked matches cerberus output +{ + level endon( "end_game" ); + level thread module_hud_full_screen_overlay(); + level thread module_hud_team_1_score( duration, fade ); + level thread module_hud_team_2_score( duration, fade ); + level thread module_hud_round_num( duration, fade ); + respawn_spectators_and_freeze_players(); + waittill_any_or_timeout( duration, "clear_hud_elems" ); +} + +respawn_spectators_and_freeze_players() //checked changed to match cerberus output +{ + players = get_players(); + foreach ( player in players ) + { + if ( player.sessionstate == "spectator" ) + { + if ( isdefined( player.spectate_hud ) ) + { + player.spectate_hud destroy(); + } + player [[ level.spawnplayer ]](); + } + player freeze_player_controls( 1 ); + } +} + +module_hud_team_1_score( duration, fade ) //checked matches cerberus output +{ + level._encounters_score_1 = newhudelem(); + level._encounters_score_1.x = 0; + level._encounters_score_1.y = 260; + level._encounters_score_1.alignx = "center"; + level._encounters_score_1.horzalign = "center"; + level._encounters_score_1.vertalign = "top"; + level._encounters_score_1.font = "default"; + level._encounters_score_1.fontscale = 2.3; + level._encounters_score_1.color = ( 1, 1, 1 ); + level._encounters_score_1.foreground = 1; + level._encounters_score_1 settext( "Team CIA: " + get_gamemode_var( "team_1_score" ) ); + level._encounters_score_1.alpha = 0; + level._encounters_score_1.sort = 11; + level._encounters_score_1 fadeovertime( fade ); + level._encounters_score_1.alpha = 1; + level waittill_any_or_timeout( duration, "clear_hud_elems" ); + level._encounters_score_1 fadeovertime( fade ); + level._encounters_score_1.alpha = 0; + wait fade; + level._encounters_score_1 destroy(); +} + +module_hud_team_2_score( duration, fade ) //checked matches cerberus output +{ + level._encounters_score_2 = newhudelem(); + level._encounters_score_2.x = 0; + level._encounters_score_2.y = 290; + level._encounters_score_2.alignx = "center"; + level._encounters_score_2.horzalign = "center"; + level._encounters_score_2.vertalign = "top"; + level._encounters_score_2.font = "default"; + level._encounters_score_2.fontscale = 2.3; + level._encounters_score_2.color = ( 1, 1, 1 ); + level._encounters_score_2.foreground = 1; + level._encounters_score_2 settext( "Team CDC: " + get_gamemode_var( "team_2_score" ) ); + level._encounters_score_2.alpha = 0; + level._encounters_score_2.sort = 12; + level._encounters_score_2 fadeovertime( fade ); + level._encounters_score_2.alpha = 1; + level waittill_any_or_timeout( duration, "clear_hud_elems" ); + level._encounters_score_2 fadeovertime( fade ); + level._encounters_score_2.alpha = 0; + wait fade; + level._encounters_score_2 destroy(); +} + +module_hud_round_num( duration, fade ) //checked matches cerberus output +{ + level._encounters_round_num = newhudelem(); + level._encounters_round_num.x = 0; + level._encounters_round_num.y = 60; + level._encounters_round_num.alignx = "center"; + level._encounters_round_num.horzalign = "center"; + level._encounters_round_num.vertalign = "top"; + level._encounters_round_num.font = "default"; + level._encounters_round_num.fontscale = 2.3; + level._encounters_round_num.color = ( 1, 1, 1 ); + level._encounters_round_num.foreground = 1; + level._encounters_round_num settext( "Round: ^5" + get_gamemode_var( "current_round" ) + 1 + " / " + get_game_var( "ZM_roundLimit" ) ); + level._encounters_round_num.alpha = 0; + level._encounters_round_num.sort = 13; + level._encounters_round_num fadeovertime( fade ); + level._encounters_round_num.alpha = 1; + level waittill_any_or_timeout( duration, "clear_hud_elems" ); + level._encounters_round_num fadeovertime( fade ); + level._encounters_round_num.alpha = 0; + wait fade; + level._encounters_round_num destroy(); +} + +createtimer() //checked matches cerberus output +{ + flag_waitopen( "pregame" ); + elem = newhudelem(); + elem.hidewheninmenu = 1; + elem.horzalign = "center"; + elem.vertalign = "top"; + elem.alignx = "center"; + elem.aligny = "middle"; + elem.x = 0; + elem.y = 0; + elem.foreground = 1; + elem.font = "default"; + elem.fontscale = 1.5; + elem.color = ( 1, 1, 1 ); + elem.alpha = 2; + elem thread maps/mp/gametypes_zm/_hud::fontpulseinit(); + if ( is_true( level.timercountdown ) ) + { + elem settenthstimer( level.timelimit * 60 ); + } + else + { + elem settenthstimerup( 0.1 ); + } + level.game_module_timer = elem; + level waittill( "game_module_ended" ); + elem destroy(); +} + +revive_laststand_players() //checked changed to match cerberus output +{ + if ( is_true( level.match_is_ending ) ) + { + return; + } + players = get_players(); + foreach ( player in players ) + { + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + player thread maps/mp/zombies/_zm_laststand::auto_revive( player ); + } + } +} + +team_icon_winner( elem ) //checked matches cerberus output +{ + og_x = elem.x; + og_y = elem.y; + elem.sort = 1; + elem scaleovertime( 0.75, 150, 150 ); + elem moveovertime( 0.75 ); + elem.horzalign = "center"; + elem.vertalign = "middle"; + elem.x = 0; + elem.y = 0; + elem.alpha = 0.7; + wait 0.75; +} + +delete_corpses() //checked changed to match cerberus output +{ + corpses = getcorpsearray(); + for(x = 0; x < corpses.size; x++) + { + corpses[x] delete(); + } +} + +track_encounters_win_stats( matchwonteam ) //checked did not change to match cerberus output +{ + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ]._encounters_team == matchwonteam ) + { + players[ i ] maps/mp/zombies/_zm_stats::increment_client_stat( "wins" ); + players[ i ] maps/mp/zombies/_zm_stats::add_client_stat( "losses", -1 ); + players[ i ] adddstat( "skill_rating", 1 ); + players[ i ] setdstat( "skill_variance", 1 ); + if ( gamemodeismode( level.gamemode_public_match ) ) + { + players[ i ] maps/mp/zombies/_zm_stats::add_location_gametype_stat( level.scr_zm_map_start_location, level.scr_zm_ui_gametype, "wins", 1 ); + players[ i ] maps/mp/zombies/_zm_stats::add_location_gametype_stat( level.scr_zm_map_start_location, level.scr_zm_ui_gametype, "losses", -1 ); + } + } + else + { + players[ i ] setdstat( "skill_rating", 0 ); + players[ i ] setdstat( "skill_variance", 1 ); + } + players[ i ] updatestatratio( "wlratio", "wins", "losses" ); + i++; + } +} + +non_round_logic( mode_logic_func ) //checked matches cerberus output +{ + level thread [[ mode_logic_func ]](); +} + +game_end_func() //checked matches cerberus output +{ + if ( !isDefined( get_gamemode_var( "match_end_notify" ) ) && !isDefined( get_gamemode_var( "match_end_func" ) ) ) + { + return; + } + level waittill( get_gamemode_var( "match_end_notify" ), winning_team ); + level thread [[ get_gamemode_var( "match_end_func" ) ]]( winning_team ); +} + +setup_classic_gametype() //checked did not change to match cerberus output +{ + ents = getentarray(); + i = 0; + while ( i < ents.size ) + { + if ( isDefined( ents[ i ].script_parameters ) ) + { + parameters = strtok( ents[ i ].script_parameters, " " ); + should_remove = 0; + foreach ( parm in parameters ) + { + if ( parm == "survival_remove" ) + { + should_remove = 1; + } + } + if ( should_remove ) + { + ents[ i ] delete(); + } + } + i++; + } + structs = getstructarray( "game_mode_object" ); + i = 0; + while ( i < structs.size ) + { + if ( !isdefined( structs[ i ].script_string ) ) + { + i++; + continue; + } + tokens = strtok( structs[ i ].script_string, " " ); + spawn_object = 0; + foreach ( parm in tokens ) + { + if ( parm == "survival" ) + { + spawn_object = 1; + } + } + if ( !spawn_object ) + { + i++; + continue; + } + barricade = spawn( "script_model", structs[ i ].origin ); + barricade.angles = structs[ i ].angles; + barricade setmodel( structs[ i ].script_parameters ); + i++; + } + unlink_meat_traversal_nodes(); +} + +zclassic_main() //checked matches cerberus output +{ + level thread setup_classic_gametype(); + level thread maps/mp/zombies/_zm::round_start(); +} + +unlink_meat_traversal_nodes() //checked changed to match cerberus output +{ + meat_town_nodes = getnodearray( "meat_town_barrier_traversals", "targetname" ); + meat_tunnel_nodes = getnodearray( "meat_tunnel_barrier_traversals", "targetname" ); + meat_farm_nodes = getnodearray( "meat_farm_barrier_traversals", "targetname" ); + nodes = arraycombine( meat_town_nodes, meat_tunnel_nodes, 1, 0 ); + traversal_nodes = arraycombine( nodes, meat_farm_nodes, 1, 0 ); + foreach ( node in traversal_nodes ) + { + end_node = getnode( node.target, "targetname" ); + unlink_nodes( node, end_node ); + } +} + +canplayersuicide() //checked matches cerberus output +{ + return self hasperk( "specialty_scavenger" ); +} + +onplayerdisconnect() //checked matches cerberus output +{ + if ( isDefined( level.game_mode_custom_onplayerdisconnect ) ) + { + level [[ level.game_mode_custom_onplayerdisconnect ]]( self ); + } + level thread maps/mp/zombies/_zm::check_quickrevive_for_hotjoin( 1 ); + self maps/mp/zombies/_zm_laststand::add_weighted_down(); + level maps/mp/zombies/_zm::checkforalldead( self ); +} + +ondeadevent( team ) //checked matches cerberus output +{ + thread maps/mp/gametypes_zm/_globallogic::endgame( level.zombie_team, "" ); +} + +onspawnintermission() //checked matches cerberus output +{ + spawnpointname = "info_intermission"; + spawnpoints = getentarray( spawnpointname, "classname" ); + if ( spawnpoints.size < 1 ) + { + /* +/# + println( "NO " + spawnpointname + " SPAWNPOINTS IN MAP" ); +#/ + */ + return; + } + spawnpoint = spawnpoints[ randomint( spawnpoints.size ) ]; + if ( isDefined( spawnpoint ) ) + { + self spawn( spawnpoint.origin, spawnpoint.angles ); + } +} + +onspawnspectator( origin, angles ) //checked matches cerberus output +{ +} + +mayspawn() //checked matches cerberus output +{ + if ( isDefined( level.custommayspawnlogic ) ) + { + return self [[ level.custommayspawnlogic ]](); + } + if ( self.pers[ "lives" ] == 0 ) + { + level notify( "player_eliminated" ); + self notify( "player_eliminated" ); + return 0; + } + return 1; +} + +onstartgametype() //checked matches cerberus output +{ + setclientnamemode( "auto_change" ); + level.displayroundendtext = 0; + maps/mp/gametypes_zm/_spawning::create_map_placed_influencers(); + if ( !isoneround() ) + { + level.displayroundendtext = 1; + if ( isscoreroundbased() ) + { + maps/mp/gametypes_zm/_globallogic_score::resetteamscores(); + } + } +} + +module_hud_full_screen_overlay() //checked matches cerberus output +{ + fadetoblack = newhudelem(); + fadetoblack.x = 0; + fadetoblack.y = 0; + fadetoblack.horzalign = "fullscreen"; + fadetoblack.vertalign = "fullscreen"; + fadetoblack setshader( "black", 640, 480 ); + fadetoblack.color = ( 1, 1, 1 ); + fadetoblack.alpha = 1; + fadetoblack.foreground = 1; + fadetoblack.sort = 0; + if ( is_encounter() || getDvar( "ui_gametype" ) == "zcleansed" ) + { + level waittill_any_or_timeout( 25, "start_fullscreen_fade_out" ); + } + else + { + level waittill_any_or_timeout( 25, "start_zombie_round_logic" ); + } + fadetoblack fadeovertime( 2 ); + fadetoblack.alpha = 0; + wait 2.1; + fadetoblack destroy(); +} + +create_final_score() //checked matches cerberus output +{ + level endon( "end_game" ); + level thread module_hud_team_winer_score(); + wait 2; +} + +module_hud_team_winer_score() //checked changed to match cerberus output +{ + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + players[ i ] thread create_module_hud_team_winer_score(); + if ( isDefined( players[ i ]._team_hud ) && isDefined( players[ i ]._team_hud[ "team" ] ) ) + { + players[ i ] thread team_icon_winner( players[ i ]._team_hud[ "team" ] ); + } + if ( isDefined( level.lock_player_on_team_score ) && level.lock_player_on_team_score ) + { + players[ i ] freezecontrols( 1 ); + players[ i ] takeallweapons(); + players[ i ] setclientuivisibilityflag( "hud_visible", 0 ); + players[ i ].sessionstate = "spectator"; + players[ i ].spectatorclient = -1; + players[ i ].maxhealth = players[ i ].health; + players[ i ].shellshocked = 0; + players[ i ].inwater = 0; + players[ i ].friendlydamage = undefined; + players[ i ].hasspawned = 1; + players[ i ].spawntime = getTime(); + players[ i ].afk = 0; + players[ i ] detachall(); + } + } + level thread maps/mp/zombies/_zm_audio::change_zombie_music( "match_over" ); +} + +create_module_hud_team_winer_score() //checked changed to match cerberus output +{ + self._team_winer_score = newclienthudelem( self ); + self._team_winer_score.x = 0; + self._team_winer_score.y = 70; + self._team_winer_score.alignx = "center"; + self._team_winer_score.horzalign = "center"; + self._team_winer_score.vertalign = "middle"; + self._team_winer_score.font = "default"; + self._team_winer_score.fontscale = 15; + self._team_winer_score.color = ( 0, 1, 0 ); + self._team_winer_score.foreground = 1; + if ( self._encounters_team == "B" && get_gamemode_var( "team_2_score" ) > get_gamemode_var( "team_1_score" ) ) + { + self._team_winer_score settext( &"ZOMBIE_MATCH_WON" ); + } + else + { + if ( self._encounters_team == "B" && get_gamemode_var( "team_2_score" ) < get_gamemode_var( "team_1_score" ) ) + { + self._team_winer_score.color = ( 1, 0, 0 ); + self._team_winer_score settext( &"ZOMBIE_MATCH_LOST" ); + } + } + if ( self._encounters_team == "A" && get_gamemode_var( "team_1_score" ) > get_gamemode_var( "team_2_score" ) ) + { + self._team_winer_score settext( &"ZOMBIE_MATCH_WON" ); + } + else + { + if ( self._encounters_team == "A" && get_gamemode_var( "team_1_score" ) < get_gamemode_var( "team_2_score" ) ) + { + self._team_winer_score.color = ( 1, 0, 0 ); + self._team_winer_score settext( &"ZOMBIE_MATCH_LOST" ); + } + } + self._team_winer_score.alpha = 0; + self._team_winer_score.sort = 12; + self._team_winer_score fadeovertime( 0.25 ); + self._team_winer_score.alpha = 1; + wait 2; + self._team_winer_score fadeovertime( 0.25 ); + self._team_winer_score.alpha = 0; + wait 0.25; + self._team_winer_score destroy(); +} + +displayroundend( round_winner ) //checked changed to match cerberus output +{ + players = get_players(); + foreach(player in players) + { + player thread module_hud_round_end( round_winner ); + if ( isdefined( player._team_hud ) && isdefined( player._team_hud[ "team" ] ) ) + { + player thread team_icon_winner( player._team_hud[ "team" ] ); + } + player freeze_player_controls( 1 ); + } + level thread maps/mp/zombies/_zm_audio::change_zombie_music( "round_end" ); + level thread maps/mp/zombies/_zm_audio::zmbvoxcrowdonteam( "clap" ); + level thread play_sound_2d( "zmb_air_horn" ); + wait 2; +} + +module_hud_round_end( round_winner ) //checked changed to match cerberus output +{ + self endon( "disconnect" ); + self._team_winner_round = newclienthudelem( self ); + self._team_winner_round.x = 0; + self._team_winner_round.y = 50; + self._team_winner_round.alignx = "center"; + self._team_winner_round.horzalign = "center"; + self._team_winner_round.vertalign = "middle"; + self._team_winner_round.font = "default"; + self._team_winner_round.fontscale = 15; + self._team_winner_round.color = ( 1, 1, 1 ); + self._team_winner_round.foreground = 1; + if ( self._encounters_team == round_winner ) + { + self._team_winner_round.color = ( 0, 1, 0 ); + self._team_winner_round settext( "YOU WIN" ); + } + else + { + self._team_winner_round.color = ( 1, 0, 0 ); + self._team_winner_round settext( "YOU LOSE" ); + } + self._team_winner_round.alpha = 0; + self._team_winner_round.sort = 12; + self._team_winner_round fadeovertime( 0.25 ); + self._team_winner_round.alpha = 1; + wait 1.5; + self._team_winner_round fadeovertime( 0.25 ); + self._team_winner_round.alpha = 0; + wait 0.25; + self._team_winner_round destroy(); +} + +displayroundswitch() //checked changed to match cerberus output +{ + level._round_changing_sides = newhudelem(); + level._round_changing_sides.x = 0; + level._round_changing_sides.y = 60; + level._round_changing_sides.alignx = "center"; + level._round_changing_sides.horzalign = "center"; + level._round_changing_sides.vertalign = "middle"; + level._round_changing_sides.font = "default"; + level._round_changing_sides.fontscale = 2.3; + level._round_changing_sides.color = ( 1, 1, 1 ); + level._round_changing_sides.foreground = 1; + level._round_changing_sides.sort = 12; + fadetoblack = newhudelem(); + fadetoblack.x = 0; + fadetoblack.y = 0; + fadetoblack.horzalign = "fullscreen"; + fadetoblack.vertalign = "fullscreen"; + fadetoblack setshader( "black", 640, 480 ); + fadetoblack.color = ( 0, 0, 0 ); + fadetoblack.alpha = 1; + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "side_switch" ); + level._round_changing_sides settext( "CHANGING SIDES" ); + level._round_changing_sides fadeovertime( 0.25 ); + level._round_changing_sides.alpha = 1; + wait 1; + fadetoblack fadeovertime( 1 ); + level._round_changing_sides fadeovertime( 0.25 ); + level._round_changing_sides.alpha = 0; + fadetoblack.alpha = 0; + wait 0.25; + level._round_changing_sides destroy(); + fadetoblack destroy(); +} + +module_hud_create_team_name() //checked matches cerberus ouput +{ + if ( !is_encounter() ) + { + return; + } + if ( !isDefined( self._team_hud ) ) + { + self._team_hud = []; + } + if ( isDefined( self._team_hud[ "team" ] ) ) + { + self._team_hud[ "team" ] destroy(); + } + elem = newclienthudelem( self ); + elem.hidewheninmenu = 1; + elem.alignx = "center"; + elem.aligny = "middle"; + elem.horzalign = "center"; + elem.vertalign = "middle"; + elem.x = 0; + elem.y = 0; + if ( isDefined( level.game_module_team_name_override_og_x ) ) + { + elem.og_x = level.game_module_team_name_override_og_x; + } + else + { + elem.og_x = 85; + } + elem.og_y = -40; + elem.foreground = 1; + elem.font = "default"; + elem.color = ( 1, 1, 1 ); + elem.sort = 1; + elem.alpha = 0.7; + elem setshader( game[ "icons" ][ self.team ], 150, 150 ); + self._team_hud[ "team" ] = elem; +} + +nextzmhud( winner ) //checked matches cerberus output +{ + displayroundend( winner ); + create_hud_scoreboard( 1, 0.25 ); + if ( checkzmroundswitch() ) + { + displayroundswitch(); + } +} + +startnextzmround( winner ) //checked matches cerberus output +{ + if ( !isonezmround() ) + { + if ( !waslastzmround() ) + { + nextzmhud( winner ); + 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" ); + if ( is_true( level.zm_switchsides_on_roundswitch ) ) + { + set_game_var( "switchedsides", !get_game_var( "switchedsides" ) ); + } + map_restart( 1 ); + return 1; + } + } + return 0; +} + +start_round() //checked changed to match cerberus output +{ + flag_clear( "start_encounters_match_logic" ); + if ( !isDefined( level._module_round_hud ) ) + { + level._module_round_hud = newhudelem(); + level._module_round_hud.x = 0; + level._module_round_hud.y = 70; + level._module_round_hud.alignx = "center"; + level._module_round_hud.horzalign = "center"; + level._module_round_hud.vertalign = "middle"; + level._module_round_hud.font = "default"; + level._module_round_hud.fontscale = 2.3; + level._module_round_hud.color = ( 1, 1, 1 ); + level._module_round_hud.foreground = 1; + level._module_round_hud.sort = 0; + } + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + players[ i ] freeze_player_controls( 1 ); + } + level._module_round_hud.alpha = 1; + label = &"Next Round Starting In ^2"; + level._module_round_hud.label = label; + level._module_round_hud settimer( 3 ); + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "countdown" ); + level thread maps/mp/zombies/_zm_audio::zmbvoxcrowdonteam( "clap" ); + level thread maps/mp/zombies/_zm_audio::change_zombie_music( "round_start" ); + level notify( "start_fullscreen_fade_out" ); + wait 2; + level._module_round_hud fadeovertime( 1 ); + level._module_round_hud.alpha = 0; + wait 1; + level thread play_sound_2d( "zmb_air_horn" ); + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + players[ i ] freeze_player_controls( 0 ); + players[ i ] sprintuprequired(); + } + flag_set( "start_encounters_match_logic" ); + flag_clear( "pregame" ); + level._module_round_hud destroy(); +} + +isonezmround() //checked matches cerberus output +{ + if ( get_game_var( "ZM_roundLimit" ) == 1 ) + { + return 1; + } + return 0; +} + +waslastzmround() //checked changed to match cerberus output +{ + if ( is_true( level.forcedend ) ) + { + return 1; + } + if ( hitzmroundlimit() || hitzmscorelimit() || hitzmroundwinlimit() ) + { + return 1; + } + return 0; +} + +hitzmroundlimit() //checked matches cerberus output +{ + if ( get_game_var( "ZM_roundLimit" ) <= 0 ) + { + return 0; + } + return getzmroundsplayed() >= get_game_var( "ZM_roundLimit" ); +} + +hitzmroundwinlimit() //checked matches cerberus output +{ + if ( !isDefined( get_game_var( "ZM_roundWinLimit" ) ) || get_game_var( "ZM_roundWinLimit" ) <= 0 ) + { + return 0; + } + if ( get_gamemode_var( "team_1_score" ) >= get_game_var( "ZM_roundWinLimit" ) || get_gamemode_var( "team_2_score" ) >= get_game_var( "ZM_roundWinLimit" ) ) + { + return 1; + } + if ( get_gamemode_var( "team_1_score" ) >= get_game_var( "ZM_roundWinLimit" ) || get_gamemode_var( "team_2_score" ) >= get_game_var( "ZM_roundWinLimit" ) ) + { + if ( get_gamemode_var( "team_1_score" ) != get_gamemode_var( "team_2_score" ) ) + { + return 1; + } + } + return 0; +} + +hitzmscorelimit() //checked matches cerberus output +{ + if ( get_game_var( "ZM_scoreLimit" ) <= 0 ) + { + return 0; + } + if ( is_encounter() ) + { + if ( get_gamemode_var( "team_1_score" ) >= get_game_var( "ZM_scoreLimit" ) || get_gamemode_var( "team_2_score" ) >= get_game_var( "ZM_scoreLimit" ) ) + { + return 1; + } + } + return 0; +} + +getzmroundsplayed() //checked matches cerberus output +{ + return get_gamemode_var( "current_round" ); +} + +onspawnplayerunified() //checked matches cerberus output +{ + onspawnplayer( 0 ); +} + +onspawnplayer( predictedspawn ) //fixed checked changed partially to match cerberus output +{ + if ( !isDefined( predictedspawn ) ) + { + predictedspawn = 0; + } + pixbeginevent( "ZSURVIVAL:onSpawnPlayer" ); + self.usingobj = undefined; + self.is_zombie = 0; + if ( isDefined( level.custom_spawnplayer ) && is_true( self.player_initialized ) ) + { + self [[ level.custom_spawnplayer ]](); + return; + } + if ( isDefined( level.customspawnlogic ) ) + { + self [[ level.customspawnlogic ]]( predictedspawn ); + if ( predictedspawn ) + { + return; + } + } + else + { + if ( flag( "begin_spawning" ) ) + { + 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" ); + if ( isdefined( structs ) ) + { + for ( i = 0; i < structs.size; i++ ) + { + if ( isdefined( structs[ i ].script_string ) ) + { + tokens = strtok( structs[ i ].script_string, " " ); + foreach ( token in tokens ) + { + if ( token == match_string ) + { + spawnpoints[ spawnpoints.size ] = structs[ i ]; + } + } + } + } + } + if ( !isDefined( spawnpoints ) || spawnpoints.size == 0 ) + { + spawnpoints = getstructarray( "initial_spawn_points", "targetname" ); + } + spawnpoint = maps/mp/zombies/_zm::getfreespawnpoint( spawnpoints, self ); + + } + if ( predictedspawn ) + { + self predictspawnpoint( spawnpoint.origin, spawnpoint.angles ); + return; + } + else + { + self spawn( spawnpoint.origin, spawnpoint.angles, "zsurvival" ); + } + } + self.entity_num = self getentitynumber(); + self thread maps/mp/zombies/_zm::onplayerspawned(); + self thread maps/mp/zombies/_zm::player_revive_monitor(); + self freezecontrols( 1 ); + self.spectator_respawn = spawnpoint; + self.score = self maps/mp/gametypes_zm/_globallogic_score::getpersstat( "score" ); + self.pers[ "participation" ] = 0; + + self.score_total = self.score; + self.old_score = self.score; + self.player_initialized = 0; + self.zombification_time = 0; + self.enabletext = 1; + self thread maps/mp/zombies/_zm_blockers::rebuild_barrier_reward_reset(); + if ( !is_true( level.host_ended_game ) ) + { + self freeze_player_controls( 0 ); + self enableweapons(); + } + if ( isDefined( level.game_mode_spawn_player_logic ) ) + { + spawn_in_spectate = [[ level.game_mode_spawn_player_logic ]](); + if ( spawn_in_spectate ) + { + self delay_thread( 0.05, maps/mp/zombies/_zm::spawnspectator ); + } + } + pixendevent(); +} + + +get_player_spawns_for_gametype() //fixed checked partially changed to match cerberus output +{ + 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; + player_spawns = []; + structs = getstructarray("player_respawn_point", "targetname"); + i = 0; + while ( i < structs.size ) + { + if ( isdefined( structs[ i ].script_string ) ) + { + tokens = strtok( structs[ i ].script_string, " " ); + foreach ( token in tokens ) + { + if ( token == match_string ) + { + player_spawns[ player_spawns.size ] = structs[ i ]; + } + } + i++; + continue; + } + player_spawns[ player_spawns.size ] = structs[ i ]; + i++; + } + return player_spawns; +} + +onendgame( winningteam ) //checked matches cerberus output +{ +} + +onroundendgame( roundwinner ) //checked matches cerberus output +{ + if ( game[ "roundswon" ][ "allies" ] == game[ "roundswon" ][ "axis" ] ) + { + winner = "tie"; + } + else if ( game[ "roundswon" ][ "axis" ] > game[ "roundswon" ][ "allies" ] ) + { + winner = "axis"; + } + else + { + winner = "allies"; + } + return winner; +} + +menu_init() //checked matches cerberus output +{ + game[ "menu_team" ] = "team_marinesopfor"; + game[ "menu_changeclass_allies" ] = "changeclass"; + game[ "menu_initteam_allies" ] = "initteam_marines"; + game[ "menu_changeclass_axis" ] = "changeclass"; + 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"; + game[ "menu_controls" ] = "ingame_controls"; + game[ "menu_options" ] = "ingame_options"; + game[ "menu_leavegame" ] = "popup_leavegame"; + game[ "menu_restartgamepopup" ] = "restartgamepopup"; + precachemenu( game[ "menu_controls" ] ); + precachemenu( game[ "menu_options" ] ); + precachemenu( game[ "menu_leavegame" ] ); + precachemenu( game[ "menu_restartgamepopup" ] ); + precachemenu( "scoreboard" ); + 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 menu_onplayerconnect(); +} + +menu_onplayerconnect() //checked matches cerberus output +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread menu_onmenuresponse(); + } +} + +menu_onmenuresponse() //checked changed to match cerberus output +{ + 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 ( self.pers[ "team" ] == "allies" ) + { + self openmenu( game[ "menu_class" ] ); + } + if ( self.pers[ "team" ] == "axis" ) + { + self openmenu( game[ "menu_class" ] ); + } + } + } + continue; + } + if ( response == "changeteam" && level.allow_teamchange == "1" ) + { + self closemenu(); + self closeingamemenu(); + self openmenu( game[ "menu_team" ] ); + } + if ( response == "changeclass_marines" ) + { + self closemenu(); + self closeingamemenu(); + self openmenu( game[ "menu_changeclass_allies" ] ); + continue; + } + if ( response == "changeclass_opfor" ) + { + self closemenu(); + self closeingamemenu(); + self openmenu( game[ "menu_changeclass_axis" ] ); + continue; + } + if ( response == "changeclass_wager" ) + { + self closemenu(); + self closeingamemenu(); + self openmenu( game[ "menu_changeclass_wager" ] ); + continue; + } + if ( response == "changeclass_custom" ) + { + self closemenu(); + self closeingamemenu(); + self openmenu( game[ "menu_changeclass_custom" ] ); + continue; + } + if ( response == "changeclass_barebones" ) + { + self closemenu(); + self closeingamemenu(); + self openmenu( game[ "menu_changeclass_barebones" ] ); + continue; + } + 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 ( is_true( level.gameended ) ) + { + self maps/mp/zombies/_zm_laststand::add_weighted_down(); + self maps/mp/zombies/_zm_stats::increment_client_stat( "deaths" ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "deaths" ); + self maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_jugg_player_death_stat(); + level.host_ended_game = 1; + maps/mp/zombies/_zm_game_module::freeze_players( 1 ); + level notify( "end_game" ); + } + } + continue; + } + if ( response == "restart_level_zm" ) + { + self maps/mp/zombies/_zm_laststand::add_weighted_down(); + self maps/mp/zombies/_zm_stats::increment_client_stat( "deaths" ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "deaths" ); + self maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_jugg_player_death_stat(); + missionfailed(); + } + if ( response == "killserverpc" ) + { + level thread maps/mp/gametypes_zm/_globallogic::killserverpc(); + continue; + } + if ( response == "endround" ) + { + if ( is_true( level.gameended ) ) + { + self maps/mp/gametypes_zm/_globallogic::gamehistoryplayerquit(); + self maps/mp/zombies/_zm_laststand::add_weighted_down(); + self closemenu(); + self closeingamemenu(); + level.host_ended_game = 1; + maps/mp/zombies/_zm_game_module::freeze_players( 1 ); + level notify( "end_game" ); + } + else + { + self closemenu(); + self closeingamemenu(); + self iprintln( &"MP_HOST_ENDGAME_RESPONSE" ); + } + continue; + } + if ( menu == game[ "menu_team" ] && level.allow_teamchange == "1" ) + { + switch( response ) + { + case "allies": + self [[ level.allies ]](); + break; + case "axis": + self [[ level.teammenu ]]( response ); + break; + case "autoassign": + self [[ level.autoassign ]]( 1 ); + break; + case "spectator": + self [[ level.spectator ]](); + 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" ) ) + { + } + self.selectedclass = 1; + self [[ level.class ]]( response ); + } + } + } +} + + +menuallieszombies() //checked changed to match cerberus output +{ + self maps/mp/gametypes_zm/_globallogic_ui::closemenus(); + if ( !level.console && level.allow_teamchange == "0" && is_true( self.hasdonecombat ) ) + { + return; + } + if ( self.pers[ "team" ] != "allies" ) + { + if ( level.ingraceperiod && !isDefined( self.hasdonecombat ) || !self.hasdonecombat ) + { + self.hasspawned = 0; + } + if ( self.sessionstate == "playing" ) + { + self.switching_teams = 1; + self.joining_team = "allies"; + self.leaving_team = self.pers[ "team" ]; + self suicide(); + } + self.pers["team"] = "allies"; + self.team = "allies"; + self.pers["class"] = undefined; + self.class = undefined; + self.pers["weapon"] = undefined; + self.pers["savedmodel"] = undefined; + self updateobjectivetext(); + if ( level.teambased ) + { + self.sessionteam = "allies"; + } + else + { + self.sessionteam = "none"; + self.ffateam = "allies"; + } + self setclientscriptmainmenu( game[ "menu_class" ] ); + self notify( "joined_team" ); + level notify( "joined_team" ); + self notify( "end_respawn" ); + } +} + + +custom_spawn_init_func() //checked matches cerberus output +{ + array_thread( level.zombie_spawners, ::add_spawn_function, maps/mp/zombies/_zm_spawner::zombie_spawn_init ); + array_thread( level.zombie_spawners, ::add_spawn_function, level._zombies_round_spawn_failsafe ); +} + +kill_all_zombies() //changed to match cerberus output +{ + ai = getaiarray( level.zombie_team ); + foreach ( zombie in ai ) + { + if ( isdefined( zombie ) ) + { + zombie dodamage( zombie.maxhealth * 2, zombie.origin, zombie, zombie, "none", "MOD_SUICIDE" ); + wait 0.05; + } + } +} + +init() //checked matches cerberus output +{ + + flag_init( "pregame" ); + flag_set( "pregame" ); + level thread onplayerconnect(); +} + +onplayerconnect() //checked matches cerberus output +{ + for ( ;; ) + { + level waittill( "connected", player ); + player thread onplayerspawned(); + if ( isDefined( level.game_module_onplayerconnect ) ) + { + player [[ level.game_module_onplayerconnect ]](); + } + } +} + +onplayerspawned() //checked partially changed to cerberus output +{ + level endon( "end_game" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill_either( "spawned_player", "fake_spawned_player" ); + if ( isDefined( level.match_is_ending ) && level.match_is_ending ) + { + return; + } + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + self thread maps/mp/zombies/_zm_laststand::auto_revive( self ); + } + if ( isDefined( level.custom_player_fake_death_cleanup ) ) + { + self [[ level.custom_player_fake_death_cleanup ]](); + } + self setstance( "stand" ); + self.zmbdialogqueue = []; + self.zmbdialogactive = 0; + self.zmbdialoggroups = []; + self.zmbdialoggroup = ""; + if ( is_encounter() ) + { + if ( self.team == "axis" ) + { + self.characterindex = 0; + self._encounters_team = "A"; + self._team_name = &"ZOMBIE_RACE_TEAM_1"; + } + else + { + self.characterindex = 1; + self._encounters_team = "B"; + self._team_name = &"ZOMBIE_RACE_TEAM_2"; + } + } + self takeallweapons(); + if ( isDefined( level.givecustomcharacters ) ) + { + self [[ level.givecustomcharacters ]](); + } + self giveweapon( "knife_zm" ); + if ( isDefined( level.onplayerspawned_restore_previous_weapons ) && isDefined( level.isresetting_grief ) && level.isresetting_grief ) + { + weapons_restored = self [[ level.onplayerspawned_restore_previous_weapons ]](); + } + if ( isDefined( weapons_restored ) && !weapons_restored || !isDefined( weapons_restored ) ) + { + self give_start_weapon( 1 ); + } + weapons_restored = 0; + if ( isDefined( level._team_loadout ) ) + { + self giveweapon( level._team_loadout ); + self switchtoweapon( level._team_loadout ); + } + if ( isDefined( level.gamemode_post_spawn_logic ) ) + { + self [[ level.gamemode_post_spawn_logic ]](); + } + } +} + +wait_for_players() //checked matches cerberus output +{ + level endon( "end_race" ); + if ( getDvarInt( "party_playerCount" ) == 1 ) + { + flag_wait( "start_zombie_round_logic" ); + return; + } + while ( !flag_exists( "start_zombie_round_logic" ) ) + { + wait 0.05; + } + while ( !flag( "start_zombie_round_logic" ) && isDefined( level._module_connect_hud ) ) + { + level._module_connect_hud.alpha = 0; + level._module_connect_hud.sort = 12; + level._module_connect_hud fadeovertime( 1 ); + level._module_connect_hud.alpha = 1; + wait 1.5; + level._module_connect_hud fadeovertime( 1 ); + level._module_connect_hud.alpha = 0; + wait 1.5; + } + if ( isDefined( level._module_connect_hud ) ) + { + level._module_connect_hud destroy(); + } +} + +onplayerconnect_check_for_hotjoin() //checked matches cerberus output +{ +/* +/# + if ( getDvarInt( #"EA6D219A" ) > 0 ) + { + return; +#/ + } +*/ + map_logic_exists = level flag_exists( "start_zombie_round_logic" ); + map_logic_started = flag( "start_zombie_round_logic" ); + if ( map_logic_exists && map_logic_started ) + { + self thread hide_gump_loading_for_hotjoiners(); + } +} + +hide_gump_loading_for_hotjoiners() //checked matches cerberus output +{ + self endon( "disconnect" ); + self.rebuild_barrier_reward = 1; + self.is_hotjoining = 1; + num = self getsnapshotackindex(); + while ( num == self getsnapshotackindex() ) + { + wait 0.25; + } + wait 0.5; + self maps/mp/zombies/_zm::spawnspectator(); + self.is_hotjoining = 0; + self.is_hotjoin = 1; + if ( is_true( level.intermission ) || is_true( level.host_ended_game ) ) + { + setclientsysstate( "levelNotify", "zi", self ); + self setclientthirdperson( 0 ); + self resetfov(); + self.health = 100; + self thread [[ level.custom_intermission ]](); + } +} + +blank() +{ + //empty function +} + + + + + + + + + + + + + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_buildables.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_buildables.gsc new file mode 100644 index 0000000..2483f2e --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_buildables.gsc @@ -0,0 +1,3146 @@ +#include maps/mp/_demo; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_buildables; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() //checked matches cerberus output +{ + precachestring( &"ZOMBIE_BUILDING" ); + precachestring( &"ZOMBIE_BUILD_PIECE_MISSING" ); + precachestring( &"ZOMBIE_BUILD_PIECE_GRAB" ); + precacheitem( "zombie_builder_zm" ); + precacheitem( "buildable_piece_zm" ); + level.gameobjswapping = 1; + zombie_buildables_callbacks = []; + level.buildablepickups = []; + level.buildables_built = []; + level.buildable_stubs = []; + level.buildable_piece_count = 0; + level._effect[ "building_dust" ] = loadfx( "maps/zombie/fx_zmb_buildable_assemble_dust" ); + if ( isDefined( level.init_buildables ) ) + { + [[ level.init_buildables ]](); + } + if ( isDefined( level.use_swipe_protection ) ) + { + onplayerconnect_callback( ::buildables_watch_swipes ); + } +} + +anystub_update_prompt( player ) //checked matches cerberus output +{ + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() || player maps/mp/zombies/_zm_utility::in_revive_trigger() ) + { + self.hint_string = ""; + return 0; + } + if ( player isthrowinggrenade() ) + { + self.hint_string = ""; + return 0; + } + if ( isDefined( player.is_drinking ) && player.is_drinking > 0 ) + { + self.hint_string = ""; + return 0; + } + if ( isDefined( player.screecher_weapon ) ) + { + self.hint_string = ""; + return 0; + } + return 1; +} + +anystub_get_unitrigger_origin() //checked matches cerberus output +{ + if ( isDefined( self.origin_parent ) ) + { + return self.origin_parent.origin; + } + return self.origin; +} + +anystub_on_spawn_trigger( trigger ) //checked matches cerberus output +{ + if ( isDefined( self.link_parent ) ) + { + trigger enablelinkto(); + trigger linkto( self.link_parent ); + trigger setmovingplatformenabled( 1 ); + } +} + +buildables_watch_swipes() //checked changed to match cerberus output +{ + self endon( "disconnect" ); + self notify( "buildables_watch_swipes" ); + self endon( "buildables_watch_swipes" ); + while ( 1 ) + { + self waittill( "melee_swipe", zombie ); + if ( distancesquared( zombie.origin, self.origin ) > zombie.meleeattackdist * zombie.meleeattackdist ) + { + continue; + } + trigger = level._unitriggers.trigger_pool[ self getentitynumber() ]; + if ( isDefined( trigger ) && isDefined( trigger.stub.piece ) ) + { + piece = trigger.stub.piece; + if ( !isDefined( piece.damage ) ) + { + piece.damage = 0; + } + piece.damage++; + if ( piece.damage > 12 ) + { + thread maps/mp/zombies/_zm_equipment::equipment_disappear_fx( trigger.stub maps/mp/zombies/_zm_unitrigger::unitrigger_origin() ); + piece maps/mp/zombies/_zm_buildables::piece_unspawn(); + self maps/mp/zombies/_zm_stats::increment_client_stat( "cheat_total", 0 ); + if ( isalive( self ) ) + { + self playlocalsound( level.zmb_laugh_alias ); + } + } + } + } +} + +explosiondamage( damage, pos ) //checked matches cerberus output +{ + /* +/# + println( "ZM BUILDABLE Explode do " + damage + " damage to " + self.name + "\n" ); +#/ + */ + self dodamage( damage, pos ); +} + +add_zombie_buildable( buildable_name, hint, building, bought ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_include_buildables ) ) + { + level.zombie_include_buildables = []; + } + if ( isDefined( level.zombie_include_buildables ) && !isDefined( level.zombie_include_buildables[ buildable_name ] ) ) + { + return; + } + precachestring( hint ); + if ( isDefined( building ) ) + { + precachestring( building ); + } + if ( isDefined( bought ) ) + { + precachestring( bought ); + } + buildable_struct = level.zombie_include_buildables[ buildable_name ]; + if ( !isDefined( level.zombie_buildables ) ) + { + level.zombie_buildables = []; + } + buildable_struct.hint = hint; + buildable_struct.building = building; + buildable_struct.bought = bought; + /* +/# + println( "ZM >> Looking for buildable - " + buildable_struct.name ); +#/ + */ + level.zombie_buildables[ buildable_struct.name ] = buildable_struct; + if ( !level.createfx_enabled ) + { + if ( level.zombie_buildables.size == 1 ) + { + register_clientfields(); + } + } +} + +register_clientfields() //checked changed to match cerberus output +{ + if ( isDefined( level.buildable_slot_count ) ) + { + for ( i = 0; i < level.buildable_slot_count; i++ ) + { + bits = getminbitcountfornum( level.buildable_piece_counts[ i ] ); + registerclientfield( "toplayer", level.buildable_clientfields[ i ], 12000, bits, "int" ); + } + } + else + { + bits = getminbitcountfornum( level.buildable_piece_count ); + registerclientfield( "toplayer", "buildable", 1, bits, "int" ); + } +} + +set_buildable_clientfield( slot, newvalue ) //checked matches cerberus output +{ + if ( isDefined( level.buildable_slot_count ) ) + { + self setclientfieldtoplayer( level.buildable_clientfields[ slot ], newvalue ); + } + else + { + self setclientfieldtoplayer( "buildable", newvalue ); + } +} + +clear_buildable_clientfield( slot ) //checked matches cerberus output +{ + self set_buildable_clientfield( slot, 0 ); +} + +include_zombie_buildable( buiildable_struct ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_include_buildables ) ) + { + level.zombie_include_buildables = []; + } + /* +/# + println( "ZM >> Including buildable - " + buiildable_struct.name ); +#/ + */ + level.zombie_include_buildables[ buiildable_struct.name ] = buiildable_struct; +} + +generate_zombie_buildable_piece( buildablename, modelname, radius, height, drop_offset, hud_icon, onpickup, ondrop, use_spawn_num, part_name, can_reuse, client_field_state, buildable_slot ) //checked changed to match cerberus output +{ + precachemodel( modelname ); + if ( isDefined( hud_icon ) ) + { + precacheshader( hud_icon ); + } + piece = spawnstruct(); + buildable_pieces = []; + buildable_pieces_structs = patch_zm\common_scripts\utility::getstructarray( buildablename + "_" + modelname, "targetname" ); + /* +/# + if ( buildable_pieces_structs.size < 1 ) + { + println( "ERROR: Missing buildable piece <" + buildablename + "> <" + modelname + ">\n" ); +#/ + } + */ + foreach ( struct in buildable_pieces_structs ) + { + buildable_pieces[ index ] = struct; + buildable_pieces[ index ].hasspawned = 0; + } + piece.spawns = buildable_pieces; + piece.buildablename = buildablename; + piece.modelname = modelname; + piece.hud_icon = hud_icon; + piece.radius = radius; + piece.height = height; + piece.part_name = part_name; + piece.can_reuse = can_reuse; + piece.drop_offset = drop_offset; + piece.max_instances = 256; + if ( isDefined( buildable_slot ) ) + { + piece.buildable_slot = buildable_slot; + } + else + { + piece.buildable_slot = 0; + } + piece.onpickup = onpickup; + piece.ondrop = ondrop; + piece.use_spawn_num = use_spawn_num; + piece.client_field_state = client_field_state; + return piece; +} + +manage_multiple_pieces( max_instances, min_instances ) //checked matches cerberus output +{ + self.max_instances = max_instances; + self.min_instances = min_instances; + self.managing_pieces = 1; + self.piece_allocated = []; +} + +buildable_set_force_spawn_location( str_kvp, str_name ) //checked matches cerberus output +{ + self.str_force_spawn_kvp = str_kvp; + self.str_force_spawn_name = str_name; +} + +buildable_use_cyclic_spawns( randomize_start_location ) //checked matches cerberus output +{ + self.use_cyclic_spawns = 1; + self.randomize_cyclic_index = randomize_start_location; +} + +combine_buildable_pieces( piece1, piece2, piece3 ) //checked matches cerberus output +{ + spawns1 = piece1.spawns; + spawns2 = piece2.spawns; + spawns = arraycombine( spawns1, spawns2, 1, 0 ); + if ( isDefined( piece3 ) ) + { + spawns3 = piece3.spawns; + spawns = arraycombine( spawns, spawns3, 1, 0 ); + spawns = array_randomize( spawns ); + piece3.spawns = spawns; + } + else + { + spawns = array_randomize( spawns ); + } + piece1.spawns = spawns; + piece2.spawns = spawns; +} + +add_buildable_piece( piece, part_name, can_reuse ) //checked matches cerberus output +{ + if ( !isDefined( self.buildablepieces ) ) + { + self.buildablepieces = []; + } + if ( isDefined( part_name ) ) + { + piece.part_name = part_name; + } + if ( isDefined( can_reuse ) ) + { + piece.can_reuse = can_reuse; + } + self.buildablepieces[ self.buildablepieces.size ] = piece; + if ( !isDefined( self.buildable_slot ) ) + { + self.buildable_slot = piece.buildable_slot; + } + else + { + /* +/# + assert( self.buildable_slot == piece.buildable_slot ); +#/ + */ + } +} + +create_zombie_buildable_piece( modelname, radius, height, hud_icon ) //checked matches cerberus output +{ + piece = generate_zombie_buildable_piece( self.name, modelname, radius, height, hud_icon ); + self add_buildable_piece( piece ); +} + +onplayerlaststand() //checked partially changed to match cerberus output +{ + pieces = self player_get_buildable_pieces(); + spawn_pos = []; + spawn_pos[ 0 ] = self.origin; + if ( pieces.size >= 2 ) + { + nodes = getnodesinradiussorted( self.origin + vectorScale( ( 0, 0, 1 ), 30 ), 120, 30, 72, "path", 5 ); + i = 0; + while ( i < pieces.size ) + { + if ( i < nodes.size && check_point_in_playable_area( nodes[ i ].origin ) ) + { + spawn_pos[ i ] = nodes[ i ].origin; + i++; + continue; + } + spawn_pos[ i ] = self.origin + vectorScale( ( 0, 0, 1 ), 5 ); + i++; + } + } + spawnidx = 0; + foreach ( piece in pieces ) + { + slot = piece.buildable_slot; + if ( isDefined( piece ) ) + { + return_to_start_pos = 0; + if ( isDefined( level.safe_place_for_buildable_piece ) ) + { + if ( !( self [[ level.safe_place_for_buildable_piece ]]( piece ) ) ) + { + return_to_start_pos = 1; + } + } + if ( return_to_start_pos ) + { + piece piece_spawn_at(); + } + else if ( pieces.size < 2 ) + { + piece piece_spawn_at( self.origin + vectorScale( ( 1, 1, 0 ), 5 ), self.angles ); + } + else + { + piece piece_spawn_at( spawn_pos[ spawnidx ], self.angles ); + } + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } + self clear_buildable_clientfield( slot ); + spawnidx++; + } + self player_set_buildable_piece( undefined, slot ); + self notify( "piece_released" + slot ); + } +} + +piecestub_get_unitrigger_origin() //checked matches cerberus output +{ + if ( isDefined( self.origin_parent ) ) + { + return self.origin_parent.origin + vectorScale( ( 0, 0, 1 ), 12 ); + } + return self.origin; +} + +generate_piece_unitrigger( classname, origin, angles, flags, radius, script_height, moving ) //checked matches cerberus output +{ + if ( !isDefined( radius ) ) + { + radius = 64; + } + if ( !isDefined( script_height ) ) + { + script_height = 64; + } + script_width = script_height; + if ( !isDefined( script_width ) ) + { + script_width = 64; + } + script_length = script_height; + if ( !isDefined( script_length ) ) + { + script_length = 64; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.origin = origin; + if ( isDefined( script_length ) ) + { + unitrigger_stub.script_length = script_length; + } + else + { + unitrigger_stub.script_length = 13.5; + } + if ( isDefined( script_width ) ) + { + unitrigger_stub.script_width = script_width; + } + else + { + unitrigger_stub.script_width = 27.5; + } + if ( isDefined( script_height ) ) + { + unitrigger_stub.script_height = script_height; + } + else + { + unitrigger_stub.script_height = 24; + } + unitrigger_stub.radius = radius; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + unitrigger_stub.hint_string = &"ZOMBIE_BUILD_PIECE_GRAB"; + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + unitrigger_stub.require_look_at = 0; + switch( classname ) + { + case "trigger_radius": + unitrigger_stub.script_unitrigger_type = "unitrigger_radius"; + break; + case "trigger_radius_use": + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + break; + case "trigger_box": + unitrigger_stub.script_unitrigger_type = "unitrigger_box"; + break; + case "trigger_box_use": + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + break; + } + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + unitrigger_stub.prompt_and_visibility_func = ::piecetrigger_update_prompt; + unitrigger_stub.originfunc = ::piecestub_get_unitrigger_origin; + unitrigger_stub.onspawnfunc = ::anystub_on_spawn_trigger; + if ( is_true( moving ) ) + { + maps/mp/zombies/_zm_unitrigger::register_unitrigger( unitrigger_stub, ::piece_unitrigger_think ); + } + else + { + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::piece_unitrigger_think ); + } + return unitrigger_stub; +} + +piecetrigger_update_prompt( player ) //checked matches cerberus output +{ + can_use = self.stub piecestub_update_prompt( player ); + self setinvisibletoplayer( player, !can_use ); + if ( isDefined( self.stub.hint_parm1 ) ) + { + self sethintstring( self.stub.hint_string, self.stub.hint_parm1 ); + } + else + { + self sethintstring( self.stub.hint_string ); + } + if ( isDefined( self.stub.cursor_hint ) ) + { + if ( self.stub.cursor_hint == "HINT_WEAPON" && isDefined( self.stub.cursor_hint_weapon ) ) + { + self setcursorhint( self.stub.cursor_hint, self.stub.cursor_hint_weapon ); + } + else + { + self setcursorhint( self.stub.cursor_hint ); + } + } + return can_use; +} + +piecestub_update_prompt( player ) //checked changed to match cerberus output +{ + if ( !self anystub_update_prompt( player ) ) + { + self.cursor_hint = "HINT_NOICON"; + return 0; + } + if ( isDefined( player player_get_buildable_piece( self.piece.buildable_slot ) ) ) + { + spiece = self.piece; + cpiece = player player_get_buildable_piece( self.piece.buildable_slot ); + if ( spiece.modelname == cpiece.modelname && spiece.buildablename == cpiece.buildablename && isDefined( spiece.script_noteworthy ) || !isDefined( cpiece.script_noteworthy ) && spiece.script_noteworthy == cpiece.script_noteworthy ) + { + self.hint_string = ""; + return 0; + } + if ( isDefined( spiece.hint_swap ) ) + { + self.hint_string = spiece.hint_swap; + self.hint_parm1 = self.piece.hint_swap_parm1; + } + else + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_SWITCH"; + } + if ( isDefined( self.piece.cursor_hint ) ) + { + self.cursor_hint = self.piece.cursor_hint; + } + if ( isDefined( self.piece.cursor_hint_weapon ) ) + { + self.cursor_hint_weapon = self.piece.cursor_hint_weapon; + } + } + else if ( isDefined( self.piece.hint_grab ) ) + { + self.hint_string = self.piece.hint_grab; + self.hint_parm1 = self.piece.hint_grab_parm1; + } + else + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_GRAB"; + } + if ( isDefined( self.piece.cursor_hint ) ) + { + self.cursor_hint = self.piece.cursor_hint; + } + if ( isDefined( self.piece.cursor_hint_weapon ) ) + { + self.cursor_hint_weapon = self.piece.cursor_hint_weapon; + } + return 1; +} + +piece_unitrigger_think() //checked changed to match cerberus output +{ + self endon( "kill_trigger" ); + while ( 1 ) + { + self waittill( "trigger", player ); + if ( player != self.parent_player ) + { + continue; + } + if ( isDefined( player.screecher_weapon ) ) + { + continue; + } + if ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + status = player player_can_take_piece( self.stub.piece ); + if ( !status ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + } + else + { + player thread player_take_piece( self.stub.piece ); + } + } +} + +player_get_buildable_pieces() //checked matches cerberus output +{ + if ( !isDefined( self.current_buildable_pieces ) ) + { + self.current_buildable_pieces = []; + } + return self.current_buildable_pieces; +} + +player_get_buildable_piece( slot ) //checked matches cerberus output +{ + if ( !isDefined( slot ) ) + { + slot = 0; + } + if ( !isDefined( self.current_buildable_pieces ) ) + { + self.current_buildable_pieces = []; + } + return self.current_buildable_pieces[ slot ]; +} + +player_set_buildable_piece( piece, slot ) //checked matches cerberus output +{ + if ( !isDefined( slot ) ) + { + slot = 0; + } + /* +/# + if ( isDefined( slot ) && isDefined( piece ) && isDefined( piece.buildable_slot ) ) + { + assert( slot == piece.buildable_slot ); +#/ + } + */ + if ( !isDefined( self.current_buildable_pieces ) ) + { + self.current_buildable_pieces = []; + } + self.current_buildable_pieces[ slot ] = piece; +} + +player_can_take_piece( piece ) //checked matches cerberus output +{ + if ( !isDefined( piece ) ) + { + return 0; + } + return 1; +} + +dbline( from, to ) //checked matches cerberus output +{ + /* +/# + time = 20; + while ( time > 0 ) + { + line( from, to, ( 0, 0, 1 ), 0, 1 ); + time -= 0.05; + wait 0.05; +#/ + } + */ +} + +player_throw_piece( piece, origin, dir, return_to_spawn, return_time, endangles ) //checked changed to match cerberus output +{ + /* +/# + assert( isDefined( piece ) ); +#/ + */ + if ( isDefined( piece ) ) + { + /* +/# + thread dbline( origin, origin + dir ); +#/ + */ + pass = 0; + done = 0; + altmodel = undefined; + while ( pass < 2 && !done ) + { + grenade = self magicgrenadetype( "buildable_piece_zm", origin, dir, 30000 ); + grenade thread watch_hit_players(); + grenade ghost(); + if ( !isDefined( altmodel ) ) + { + altmodel = spawn( "script_model", grenade.origin ); + altmodel setmodel( piece.modelname ); + } + altmodel.origin = grenade.angles; + altmodel.angles = grenade.angles; + altmodel linkto( grenade, "", ( 0, 0, 0 ), ( 0, 0, 0 ) ); + grenade.altmodel = altmodel; + grenade waittill( "stationary" ); + grenade_origin = grenade.origin; + grenade_angles = grenade.angles; + landed_on = grenade getgroundent(); + grenade delete(); + if ( isDefined( landed_on ) && landed_on == level ) + { + done = 1; + } + else + { + origin = grenade_origin; + dir = ( ( dir[ 0 ] * -1 ) / 10, ( dir[ 1 ] * -1 ) / 10, -1 ); + pass++; + } + } + if ( !isDefined( endangles ) ) + { + endangles = grenade_angles; + } + piece piece_spawn_at( grenade_origin, endangles ); + if ( isDefined( altmodel ) ) + { + altmodel delete(); + } + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } + if ( is_true( return_to_spawn ) ) + { + piece piece_wait_and_return( return_time ); + } + } +} + +watch_hit_players() //checked matches cerberus output +{ + self endon( "death" ); + self endon( "stationary" ); + while ( isDefined( self ) ) + { + self waittill( "grenade_bounce", pos, normal, ent ); + if ( isplayer( ent ) ) + { + ent explosiondamage( 25, pos ); + } + } +} + +piece_wait_and_return( return_time ) //checked matches cerberus output +{ + self endon( "pickup" ); + wait 0.15; + if ( isDefined( level.exploding_jetgun_fx ) ) + { + playfxontag( level.exploding_jetgun_fx, self.model, "tag_origin" ); + } + else + { + playfxontag( level._effect[ "powerup_on" ], self.model, "tag_origin" ); + } + wait ( return_time - 6 ); + self piece_hide(); + wait 1; + self piece_show(); + wait 1; + self piece_hide(); + wait 1; + self piece_show(); + wait 1; + self piece_hide(); + wait 1; + self piece_show(); + wait 1; + self notify( "respawn" ); + self piece_unspawn(); + self piece_spawn_at(); +} + +player_return_piece_to_original_spawn( slot ) //checked matches cerberus output +{ + if ( !isDefined( slot ) ) + { + slot = 0; + } + self notify( "piece_released" + slot ); + piece = self player_get_buildable_piece( slot ); + self player_set_buildable_piece( undefined, slot ); + if ( isDefined( piece ) ) + { + piece piece_spawn_at(); + self clear_buildable_clientfield( slot ); + } +} + +player_drop_piece_on_death( slot ) //checked matches cerberus output +{ + self notify( "piece_released" + slot ); + self endon( "piece_released" + slot ); + origin = self.origin; + angles = self.angles; + piece = self player_get_buildable_piece( slot ); + self waittill( "death_or_disconnect" ); + piece piece_spawn_at( origin, angles ); + if ( isDefined( self ) ) + { + self clear_buildable_clientfield( slot ); + } + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } +} + +player_drop_piece( piece, slot ) //checked matches cerberus output +{ + if ( !isDefined( slot ) ) + { + slot = 0; + } + if ( !isDefined( piece ) ) + { + piece = self player_get_buildable_piece( slot ); + } + else + { + slot = piece.buildable_slot; + } + if ( isDefined( piece ) ) + { + origin = self.origin; + origintrace = groundtrace( origin + vectorScale( ( 0, 0, 1 ), 5 ), origin - vectorScale( ( 0, 0, 1 ), 999999 ), 0, self ); + if ( isDefined( origintrace[ "entity" ] ) ) + { + origintrace = groundtrace( origintrace[ "entity" ].origin, origintrace[ "entity" ].origin - vectorScale( ( 0, 0, 1 ), 999999 ), 0, origintrace[ "entity" ] ); + } + if ( isDefined( origintrace[ "position" ] ) ) + { + origin = origintrace[ "position" ]; + } + piece.damage = 0; + piece piece_spawn_at( origin, self.angles ); + if ( isplayer( self ) ) + { + self clear_buildable_clientfield( slot ); + } + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } + } + self player_set_buildable_piece( undefined, slot ); + self notify( "piece_released" + slot ); +} + +player_take_piece( piece ) //checked matches cerberus output +{ + piece_slot = piece.buildable_slot; + damage = piece.damage; + if ( isDefined( self player_get_buildable_piece( piece_slot ) ) ) + { + other_piece = self player_get_buildable_piece( piece_slot ); + self player_drop_piece( self player_get_buildable_piece( piece_slot ), piece_slot ); + other_piece.damage = damage; + self do_player_general_vox( "general", "build_swap" ); + } + if ( isDefined( piece.onpickup ) ) + { + piece [[ piece.onpickup ]]( self ); + } + piece piece_unspawn(); + piece notify( "pickup" ); + if ( isplayer( self ) ) + { + if ( isDefined( piece.client_field_state ) ) + { + self set_buildable_clientfield( piece_slot, piece.client_field_state ); + } + self player_set_buildable_piece( piece, piece_slot ); + self thread player_drop_piece_on_death( piece_slot ); + self track_buildable_piece_pickedup( piece ); + } +} + +player_destroy_piece( piece ) //checked matches cerberus output +{ + if ( !isDefined( piece ) ) + { + piece = self player_get_buildable_piece(); + } + if ( isplayer( self ) ) + { + slot = piece.buildable_slot; + if ( isDefined( piece ) ) + { + piece piece_destroy(); + self clear_buildable_clientfield( slot ); + } + self player_set_buildable_piece( undefined, slot ); + self notify( "piece_released" + slot ); + } +} + +claim_location( location ) //checked matches cerberus output +{ + if ( !isDefined( level.buildable_claimed_locations ) ) + { + level.buildable_claimed_locations = []; + } + if ( !isDefined( level.buildable_claimed_locations[ location ] ) ) + { + level.buildable_claimed_locations[ location ] = 1; + return 1; + } + return 0; +} + +is_point_in_build_trigger( point ) //checked changed to match cerberus output +{ + candidate_list = []; + foreach ( zone in level.zones ) + { + if ( isDefined( zone.unitrigger_stubs ) ) + { + candidate_list = arraycombine( candidate_list, zone.unitrigger_stubs, 1, 0 ); + } + } + valid_range = 128; + closest = maps/mp/zombies/_zm_unitrigger::get_closest_unitriggers( point, candidate_list, valid_range ); + for ( index = 0; index < closest.size; index++ ) + { + if ( isDefined( closest[ index ].registered ) && closest[ index ].registered && isDefined( closest[ index ].piece ) ) + { + return 1; + } + } + return 0; +} + +piece_allocate_spawn( piecespawn ) //checked changed to match cerberus output +{ + self.current_spawn = 0; + self.managed_spawn = 1; + self.piecespawn = piecespawn; + if ( isDefined( piecespawn.str_force_spawn_kvp ) ) + { + s_struct = patch_zm\common_scripts\utility::getstruct( piecespawn.str_force_spawn_name, piecespawn.str_force_spawn_kvp ); + if ( isDefined( s_struct ) ) + { + for ( i = 0; i < self.spawns.size; i++ ) + { + if ( s_struct == self.spawns[ i ] ) + { + self.current_spawn = i; + piecespawn.piece_allocated[ self.current_spawn ] = 1; + piecespawn.str_force_spawn_kvp = undefined; + piecespawn.str_force_spawn_name = undefined; + return; + } + } + } + } + else if ( isDefined( piecespawn.use_cyclic_spawns ) ) + { + piece_allocate_cyclic( piecespawn ); + return; + } + if ( self.spawns.size >= 1 && self.spawns.size > 1 ) + { + any_good = 0; + any_okay = 0; + totalweight = 0; + spawnweights = []; + for ( i = 0; i < self.spawns.size; i++ ) + { + if ( isDefined( piecespawn.piece_allocated[ i ] ) && piecespawn.piece_allocated[ i ] ) + { + spawnweights[ i ] = 0; + } + else if ( isDefined( self.spawns[ i ].script_forcespawn ) && self.spawns[ i ].script_forcespawn ) + { + switch( self.spawns[ i ].script_forcespawn ) + { + case 4: + spawnweights[ i ] = 0; + break; + case 1: + self.spawns[ i ].script_forcespawn = 0; + case 2: + self.current_spawn = i; + piecespawn.piece_allocated[ self.current_spawn ] = 1; + return; + case 3: + self.spawns[ i ].script_forcespawn = 4; + self.current_spawn = i; + piecespawn.piece_allocated[ self.current_spawn ] = 1; + return; + default: + any_okay = 1; + spawnweights[ i ] = 0.01; + break; + } + } + else if ( is_point_in_build_trigger( self.spawns[ i ].origin ) ) + { + any_okay = 1; + spawnweights[ i ] = 0.01; + break; + } + else + { + any_good = 1; + spawnweights[ i ] = 1; + } + totalweight += spawnweights[ i ]; + } + /* +/# + if ( !any_good ) + { + assert( any_okay, "There is nowhere to spawn this piece" ); + } +#/ + */ + if ( any_good ) + { + totalweight = float( int( totalweight ) ); + } + r = randomfloat( totalweight ); + for ( i = 0; i < self.spawns.size; i++ ) + { + if ( !any_good || spawnweights[ i ] >= 1 ) + { + r -= spawnweights[ i ]; + if ( r < 0 ) + { + self.current_spawn = i; + piecespawn.piece_allocated[ self.current_spawn ] = 1; + return; + } + } + } + self.current_spawn = randomint( self.spawns.size ); + piecespawn.piece_allocated[ self.current_spawn ] = 1; + } +} + +piece_allocate_cyclic( piecespawn ) //checked matches cerberus output +{ + if ( self.spawns.size > 1 ) + { + if ( isDefined( piecespawn.randomize_cyclic_index ) ) + { + piecespawn.randomize_cyclic_index = undefined; + piecespawn.cyclic_index = randomint( self.spawns.size ); + } + if ( !isDefined( piecespawn.cyclic_index ) ) + { + piecespawn.cyclic_index = 0; + } + piecespawn.cyclic_index++; + if ( piecespawn.cyclic_index >= self.spawns.size ) + { + piecespawn.cyclic_index = 0; + } + } + else + { + piecespawn.cyclic_index = 0; + } + self.current_spawn = piecespawn.cyclic_index; + piecespawn.piece_allocated[ self.current_spawn ] = 1; +} + +piece_deallocate_spawn() //checked matches cerberus output +{ + if ( isDefined( self.current_spawn ) ) + { + self.piecespawn.piece_allocated[ self.current_spawn ] = 0; + self.current_spawn = undefined; + } + self.start_origin = undefined; +} + +piece_pick_random_spawn() //checked partially changed to match cerberus output did not change while loop to for loop +{ + self.current_spawn = 0; + if ( self.spawns.size >= 1 && self.spawns.size > 1 ) + { + self.current_spawn = randomint( self.spawns.size ); + while ( isDefined( self.spawns[ self.current_spawn ].claim_location ) && !claim_location( self.spawns[ self.current_spawn ].claim_location ) ) + { + arrayremoveindex( self.spawns, self.current_spawn ); + if ( self.spawns.size < 1 ) + { + self.current_spawn = 0; + /* +/# + println( "ERROR: All buildable spawn locations claimed" ); +#/ + */ + return; + } + self.current_spawn = randomint( self.spawns.size ); + } + } +} + +piece_set_spawn( num ) //checked matches cerberus output +{ + self.current_spawn = 0; + if ( self.spawns.size >= 1 && self.spawns.size > 1 ) + { + self.current_spawn = int( min( num, self.spawns.size - 1 ) ); + } +} + +piece_spawn_in( piecespawn ) //checked matches cerberus output +{ + if ( self.spawns.size < 1 ) + { + return; + } + if ( is_true( self.managed_spawn ) ) + { + if ( !isDefined( self.current_spawn ) ) + { + self piece_allocate_spawn( self.piecespawn ); + } + } + if ( !isDefined( self.current_spawn ) ) + { + self.current_spawn = 0; + } + spawndef = self.spawns[ self.current_spawn ]; + self.script_noteworthy = spawndef.script_noteworthy; + self.script_parameters = spawndef.script_parameters; + self.unitrigger = generate_piece_unitrigger( "trigger_radius_use", spawndef.origin + vectorScale( ( 0, 0, 1 ), 12 ), spawndef.angles, 0, piecespawn.radius, piecespawn.height, 0 ); + self.unitrigger.piece = self; + self.buildable_slot = piecespawn.buildable_slot; + self.radius = piecespawn.radius; + self.height = piecespawn.height; + self.buildablename = piecespawn.buildablename; + self.modelname = piecespawn.modelname; + self.hud_icon = piecespawn.hud_icon; + self.part_name = piecespawn.part_name; + self.drop_offset = piecespawn.drop_offset; + self.start_origin = spawndef.origin; + self.start_angles = spawndef.angles; + self.client_field_state = piecespawn.client_field_state; + self.hint_grab = piecespawn.hint_grab; + self.hint_swap = piecespawn.hint_swap; + self.model = spawn( "script_model", self.start_origin ); + if ( isDefined( self.start_angles ) ) + { + self.model.angles = self.start_angles; + } + self.model setmodel( piecespawn.modelname ); + self.model ghostindemo(); + self.model.hud_icon = piecespawn.hud_icon; + self.piecespawn = piecespawn; + self.unitrigger.origin_parent = self.model; + self.building = undefined; + self.onunspawn = piecespawn.onunspawn; + self.ondestroy = piecespawn.ondestroy; + if ( isDefined( piecespawn.onspawn ) ) + { + self.onspawn = piecespawn.onspawn; + self [[ piecespawn.onspawn ]](); + } +} + +piece_spawn_at_with_notify_delay( origin, angles, str_notify, unbuild_respawn_fn ) //checked matches cerberus output +{ + level waittill( str_notify ); + piece_spawn_at( origin, angles ); + if ( isDefined( unbuild_respawn_fn ) ) + { + self [[ unbuild_respawn_fn ]](); + } +} + +piece_spawn_at( origin, angles ) //checked changed to match cerberus output +{ + if ( self.spawns.size < 1 ) + { + return; + } + if ( is_true( self.managed_spawn ) ) + { + if ( !isDefined( self.current_spawn ) && !isDefined( origin ) ) + { + self piece_allocate_spawn( self.piecespawn ); + spawndef = self.spawns[ self.current_spawn ]; + self.start_origin = spawndef.origin; + self.start_angles = spawndef.angles; + } + } + else if ( !isDefined( self.current_spawn ) ) + { + self.current_spawn = 0; + } + unitrigger_offset = vectorScale( ( 0, 0, 1 ), 12 ); + if ( !isDefined( origin ) ) + { + origin = self.start_origin; + } + else + { + origin += ( 0, 0, self.drop_offset ); + unitrigger_offset -= ( 0, 0, self.drop_offset ); + } + if ( !isDefined( angles ) ) + { + angles = self.start_angles; + } + /* +/# + if ( !isDefined( level.drop_offset ) ) + { + level.drop_offset = 0; + } + origin += ( 0, 0, level.drop_offset ); + unitrigger_offset -= ( 0, 0, level.drop_offset ); +#/ + */ + self.model = spawn( "script_model", origin ); + if ( isDefined( angles ) ) + { + self.model.angles = angles; + } + self.model setmodel( self.modelname ); + if ( isDefined( level.equipment_safe_to_drop ) ) + { + if ( ![[ level.equipment_safe_to_drop ]]( self.model ) ) + { + origin = self.start_origin; + angles = self.start_angles; + self.model.origin = origin; + self.model.angles = angles; + } + } + if ( isDefined( self.model.canmove ) ) + { + self.unitrigger = generate_piece_unitrigger( "trigger_radius_use", origin + unitrigger_offset, angles, 0, self.radius, self.height, self.model.canmove ); + } + self.unitrigger.piece = self; + self.model.hud_icon = self.hud_icon; + self.unitrigger.origin_parent = self.model; + self.building = undefined; + if ( isDefined( self.onspawn ) ) + { + self [[ self.onspawn ]](); + } +} + +piece_unspawn() //checked matches cerberus output +{ + if ( isDefined( self.onunspawn ) ) + { + self [[ self.onunspawn ]](); + } + if ( is_true( self.managed_spawn ) ) + { + self piece_deallocate_spawn(); + } + if ( isDefined( self.model ) ) + { + self.model delete(); + } + self.model = undefined; + if ( isDefined( self.unitrigger ) ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.unitrigger ); + } + self.unitrigger = undefined; +} + +piece_hide() //checked matches cerberus output +{ + if ( isDefined( self.model ) ) + { + self.model ghost(); + } +} + +piece_show() //checked matches cerberus output +{ + if ( isDefined( self.model ) ) + { + self.model show(); + } +} + +piece_destroy() //checked matches cerberus output +{ + if ( isDefined( self.ondestroy ) ) + { + self [[ self.ondestroy ]](); + } +} + +generate_piece( buildable_piece_spawns ) //checked changed to match cerberus output +{ + piece = spawnstruct(); + piece.spawns = buildable_piece_spawns.spawns; + if ( isDefined( buildable_piece_spawns.managing_pieces ) && buildable_piece_spawns.managing_pieces ) + { + piece piece_allocate_spawn( buildable_piece_spawns ); + } + else if ( isDefined( buildable_piece_spawns.use_spawn_num ) ) + { + piece piece_set_spawn( buildable_piece_spawns.use_spawn_num ); + } + else + { + piece piece_pick_random_spawn(); + } + piece piece_spawn_in( buildable_piece_spawns ); + if ( piece.spawns.size >= 1 ) + { + piece.hud_icon = buildable_piece_spawns.hud_icon; + } + if ( isDefined( buildable_piece_spawns.onpickup ) ) + { + piece.onpickup = buildable_piece_spawns.onpickup; + } + else + { + piece.onpickup = ::onpickuputs; + } + if ( isDefined( buildable_piece_spawns.ondrop ) ) + { + piece.ondrop = buildable_piece_spawns.ondrop; + } + else + { + piece.ondrop = ::ondroputs; + } + return piece; +} + +buildable_piece_unitriggers( buildable_name, origin ) //checked changed to match cerberus output +{ + /* +/# + assert( isDefined( buildable_name ) ); +#/ +/# + assert( isDefined( level.zombie_buildables[ buildable_name ] ), "Called buildable_think() without including the buildable - " + buildable_name ); +#/ + */ + buildable = level.zombie_buildables[ buildable_name ]; + if ( !isDefined( buildable.buildablepieces ) ) + { + buildable.buildablepieces = []; + } + flag_wait( "start_zombie_round_logic" ); + buildablezone = spawnstruct(); + buildablezone.buildable_name = buildable_name; + buildablezone.buildable_slot = buildable.buildable_slot; + if ( !isDefined( buildablezone.pieces ) ) + { + buildablezone.pieces = []; + } + buildablepickups = []; + foreach ( buildablepiece in buildable.buildablepieces ) + { + if ( !isDefined( buildablepiece.generated_instances ) ) + { + buildablepiece.generated_instances = 0; + } + if ( isDefined( buildablepiece.generated_piece ) && is_true( buildablepiece.can_reuse ) ) + { + piece = buildablepiece.generated_piece; + break; + } + if ( buildablepiece.generated_instances >= buildablepiece.max_instances ) + { + piece = buildablepiece.generated_piece; + break; + } + piece = generate_piece( buildablepiece ); + buildablepiece.generated_piece = piece; + buildablepiece.generated_instances++; + if ( isDefined( buildablepiece.min_instances ) ) + { + while ( buildablepiece.generated_instances < buildablepiece.min_instances ) + { + piece = generate_piece( buildablepiece ); + buildablepiece.generated_piece = piece; + buildablepiece.generated_instances++; + } + } + buildablezone.pieces[ buildablezone.pieces.size ] = piece; + } + buildablezone.stub = self; + return buildablezone; +} + +hide_buildable_table_model( trigger_targetname ) //checked matches cerberus output +{ + trig = getent( trigger_targetname, "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + if ( isDefined( trig.target ) ) + { + model = getent( trig.target, "targetname" ); + if ( isDefined( model ) ) + { + model hide(); + model notsolid(); + } + } +} + +setup_unitrigger_buildable( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) //checked matches cerberus output +{ + trig = getent( trigger_targetname, "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + return setup_unitrigger_buildable_internal( trig, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +setup_unitrigger_buildable_array( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) //checked changed to match cerberus output +{ + triggers = getentarray( trigger_targetname, "targetname" ); + stubs = []; + foreach ( trig in triggers ) + { + stubs[ stubs.size ] = setup_unitrigger_buildable_internal( trig, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); + } + return stubs; +} + +setup_unitrigger_buildable_internal( trig, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) //checked changed to match cerberus output +{ + if ( !isDefined( trig ) ) + { + return; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.buildablestruct = level.zombie_include_buildables[ equipname ]; + angles = trig.script_angles; + if ( !isDefined( angles ) ) + { + angles = ( 0, 0, 0 ); + } + unitrigger_stub.origin = trig.origin + ( anglesToRight( angles ) * -6 ); + unitrigger_stub.angles = trig.angles; + if ( isDefined( trig.script_angles ) ) + { + unitrigger_stub.angles = trig.script_angles; + } + unitrigger_stub.equipname = equipname; + unitrigger_stub.weaponname = weaponname; + unitrigger_stub.trigger_hintstring = trigger_hintstring; + unitrigger_stub.delete_trigger = delete_trigger; + unitrigger_stub.built = 0; + unitrigger_stub.persistent = persistent; + unitrigger_stub.usetime = int( 3000 ); + unitrigger_stub.onbeginuse = ::onbeginuseuts; + unitrigger_stub.onenduse = ::onenduseuts; + unitrigger_stub.onuse = ::onuseplantobjectuts; + unitrigger_stub.oncantuse = ::oncantuseuts; + if ( isDefined( trig.script_length ) ) + { + unitrigger_stub.script_length = trig.script_length; + } + else + { + unitrigger_stub.script_length = 32; + } + if ( isDefined( trig.script_width ) ) + { + unitrigger_stub.script_width = trig.script_width; + } + else + { + unitrigger_stub.script_width = 100; + } + if ( isDefined( trig.script_height ) ) + { + unitrigger_stub.script_height = trig.script_height; + } + else + { + unitrigger_stub.script_height = 64; + } + unitrigger_stub.target = trig.target; + unitrigger_stub.targetname = trig.targetname; + unitrigger_stub.script_noteworthy = trig.script_noteworthy; + unitrigger_stub.script_parameters = trig.script_parameters; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + if ( isDefined( level.zombie_buildables[ equipname ].hint ) ) + { + unitrigger_stub.hint_string = level.zombie_buildables[ equipname ].hint; + } + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + unitrigger_stub.require_look_at = 1; + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + unitrigger_stub.prompt_and_visibility_func = ::buildabletrigger_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::buildable_place_think ); + unitrigger_stub.piece_trigger = trig; + trig.trigger_stub = unitrigger_stub; + unitrigger_stub.zombie_weapon_upgrade = trig.zombie_weapon_upgrade; + if ( isDefined( unitrigger_stub.target ) ) + { + unitrigger_stub.model = getent( unitrigger_stub.target, "targetname" ); + if ( isDefined( unitrigger_stub.model ) ) + { + if ( isDefined( unitrigger_stub.zombie_weapon_upgrade ) ) + { + unitrigger_stub.model useweaponhidetags( unitrigger_stub.zombie_weapon_upgrade ); + } + unitrigger_stub.model hide(); + unitrigger_stub.model notsolid(); + } + } + unitrigger_stub.buildablezone = unitrigger_stub buildable_piece_unitriggers( equipname, unitrigger_stub.origin ); + if ( delete_trigger ) + { + trig delete(); + } + level.buildable_stubs[ level.buildable_stubs.size ] = unitrigger_stub; + return unitrigger_stub; +} + +buildable_has_piece( piece ) //checked changed to match cerberus output +{ + for ( i = 0; i < self.pieces.size; i++ ) + { + if ( self.pieces[ i ].modelname == piece.modelname && self.pieces[ i ].buildablename == piece.buildablename ) + { + return 1; + } + } + return 0; +} + +buildable_set_piece_built( piece ) //checked changed to match cerberus output +{ + for ( i = 0; i < self.pieces.size; i++ ) + { + if ( self.pieces[ i ].modelname == piece.modelname && self.pieces[ i ].buildablename == piece.buildablename ) + { + self.pieces[ i ].built = 1; + } + } +} + +buildable_set_piece_building( piece ) //checked changed to match cerberus output +{ + for ( i = 0; i < self.pieces.size; i++ ) + { + if ( self.pieces[ i ].modelname == piece.modelname && self.pieces[ i ].buildablename == piece.buildablename ) + { + self.pieces[ i ] = piece; + self.pieces[ i ].building = 1; + } + } +} + +buildable_clear_piece_building( piece ) //checked matches cerberus output +{ + if ( isDefined( piece ) ) + { + piece.building = 0; + } +} + +buildable_is_piece_built( piece ) //checked partially changed to match cerberus output //changed at own discretion +{ + for ( i = 0; i < self.pieces.size; i++ ) + { + if ( self.pieces[ i ].modelname == piece.modelname && self.pieces[ i ].buildablename == piece.buildablename ) + { + if ( isDefined( self.pieces[ i ].built ) && self.pieces[ i ].built ) + { + return 1; + } + } + } + return 0; +} + +buildable_is_piece_building( piece ) +{ + for ( i = 0; i < self.pieces.size; i++ ) + { + if ( self.pieces[ i ].modelname == piece.modelname && self.pieces[ i ].buildablename == piece.buildablename ) + { + if ( isDefined( self.pieces[ i ].building ) && self.pieces[ i ].building && self.pieces[ i ] == piece ) + { + return 1; + } + } + } + return 0; +} + +buildable_is_piece_built_or_building( piece ) //checked partially changed to match cerberus output //changed at own discretion +{ + for ( i = 0; i < self.pieces.size; i++ ) + { + if ( self.pieces[ i ].modelname == piece.modelname && self.pieces[ i ].buildablename == piece.buildablename ) + { + if ( !is_true( self.pieces[ i ].built ) ) + { + if ( is_true( self.pieces[ i ].building ) ) + { + return 1; + } + } + } + i++; + } + return 0; +} + +buildable_all_built() //checked changed to match cerberus output +{ + for ( i = 0; i < self.pieces.size; i++ ) + { + if ( !is_true( self.pieces[ i ].built ) ) + { + return 0; + } + } + return 1; +} + +player_can_build( buildable, continuing ) //checked changed to match cerberus output +{ + if ( !isDefined( buildable ) ) + { + return 0; + } + if ( !isDefined( self player_get_buildable_piece( buildable.buildable_slot ) ) ) + { + return 0; + } + if ( !buildable buildable_has_piece( self player_get_buildable_piece( buildable.buildable_slot ) ) ) + { + return 0; + } + if ( is_true( continuing ) ) + { + if ( buildable buildable_is_piece_built( self player_get_buildable_piece( buildable.buildable_slot ) ) ) + { + return 0; + } + } + else if ( buildable buildable_is_piece_built_or_building( self player_get_buildable_piece( buildable.buildable_slot ) ) ) + { + return 0; + } + if ( isDefined( buildable.stub ) && isDefined( buildable.stub.custom_buildablestub_update_prompt ) && isDefined( buildable.stub.playertrigger[ 0 ] ) && isDefined( buildable.stub.playertrigger[ 0 ].stub ) && !( buildable.stub.playertrigger[ 0 ].stub [[ buildable.stub.custom_buildablestub_update_prompt ]]( self, 1, buildable.stub.playertrigger[ 0 ] ) ) ) + { + return 0; + } + return 1; +} + +player_build( buildable, pieces ) //checked partially changed to match cerberus output +{ + if ( isDefined( pieces ) ) + { + for ( i = 0; i < pieces.size; i++ ) + { + buildable buildable_set_piece_built( pieces[ i ] ); + player_destroy_piece( pieces[ i ] ); + } + } + else + { + buildable buildable_set_piece_built( self player_get_buildable_piece( buildable.buildable_slot ) ); + player_destroy_piece( self player_get_buildable_piece( buildable.buildable_slot ) ); + } + if ( isDefined( buildable.stub.model ) ) + { + i = 0; + while ( i < buildable.pieces.size ) + { + if ( isDefined( buildable.pieces[ i ].part_name ) ) + { + buildable.stub.model notsolid(); + if ( !is_true( buildable.pieces[ i ].built ) ) + { + buildable.stub.model hidepart( buildable.pieces[ i ].part_name ); + i++; + continue; + } + buildable.stub.model show(); + buildable.stub.model showpart( buildable.pieces[ i ].part_name ); + } + i++; + } + } + else if ( isplayer( self ) ) + { + self track_buildable_pieces_built( buildable ); + } + if ( buildable buildable_all_built() ) + { + self player_finish_buildable( buildable ); + buildable.stub buildablestub_finish_build( self ); + if ( isplayer( self ) ) + { + self track_buildables_built( buildable ); + } + if ( isDefined( level.buildable_built_custom_func ) ) + { + self thread [[ level.buildable_built_custom_func ]]( buildable ); + } + alias = sndbuildablecompletealias( buildable.buildable_name ); + self playsound( alias ); + } + else + { + self playsound( "zmb_buildable_piece_add" ); + /* +/# + assert( isDefined( level.zombie_buildables[ buildable.buildable_name ].building ), "Missing builing hint" ); +#/ + */ + if ( isDefined( level.zombie_buildables[ buildable.buildable_name ].building ) ) + { + return level.zombie_buildables[ buildable.buildable_name ].building; + } + } + return ""; +} + +sndbuildablecompletealias( name ) //checked matches cerberus output +{ + alias = undefined; + switch( name ) + { + case "chalk": + alias = "zmb_chalk_complete"; + break; + default: + alias = "zmb_buildable_complete"; + break; + } + return alias; +} + +player_finish_buildable( buildable ) //checked matches cerberus output +{ + buildable.built = 1; + buildable.stub.built = 1; + buildable notify( "built" ); + level.buildables_built[ buildable.buildable_name ] = 1; + level notify( buildable.buildable_name + "_built" ); +} + +buildablestub_finish_build( player ) //checked matches cerberus output +{ + player player_finish_buildable( self.buildablezone ); +} + +buildablestub_remove() //checked matches cerberus output +{ + arrayremovevalue( level.buildable_stubs, self ); +} + +buildabletrigger_update_prompt( player ) //checked matches cerberus output +{ + can_use = self.stub buildablestub_update_prompt( player ); + self sethintstring( self.stub.hint_string ); + if ( isDefined( self.stub.cursor_hint ) ) + { + if ( self.stub.cursor_hint == "HINT_WEAPON" && isDefined( self.stub.cursor_hint_weapon ) ) + { + self setcursorhint( self.stub.cursor_hint, self.stub.cursor_hint_weapon ); + } + else + { + self setcursorhint( self.stub.cursor_hint ); + } + } + return can_use; +} + +buildablestub_update_prompt( player ) //checked changed to match cerberus output +{ + if ( !self anystub_update_prompt( player ) ) + { + return 0; + } + can_use = 1; + if ( isDefined( self.buildablestub_reject_func ) ) + { + rval = self [[ self.buildablestub_reject_func ]]( player ); + if ( rval ) + { + return 0; + } + } + if ( isDefined( self.custom_buildablestub_update_prompt ) && !self [[ self.custom_buildablestub_update_prompt ]]( player ) ) + { + return 0; + } + self.cursor_hint = "HINT_NOICON"; + self.cursor_hint_weapon = undefined; + if ( isDefined( self.built ) && !self.built ) + { + slot = self.buildablestruct.buildable_slot; + if ( !isDefined( player player_get_buildable_piece( slot ) ) ) + { + if ( isDefined( level.zombie_buildables[ self.equipname ].hint_more ) ) + { + self.hint_string = level.zombie_buildables[ self.equipname ].hint_more; + } + else + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_MORE"; + } + return 0; + } + else if ( !self.buildablezone buildable_has_piece( player player_get_buildable_piece( slot ) ) ) + { + if ( isDefined( level.zombie_buildables[ self.equipname ].hint_wrong ) ) + { + self.hint_string = level.zombie_buildables[ self.equipname ].hint_wrong; + } + else + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_WRONG"; + } + return 0; + } + else + { + /* + /# + assert( isDefined( level.zombie_buildables[ self.equipname ].hint ), "Missing buildable hint" ); + #/ + */ + if ( isDefined( level.zombie_buildables[ self.equipname ].hint ) ) + { + self.hint_string = level.zombie_buildables[ self.equipname ].hint; + } + else + { + self.hint_string = "Missing buildable hint"; + } + } + } + else if ( self.persistent == 1 ) + { + if ( maps/mp/zombies/_zm_equipment::is_limited_equipment( self.weaponname ) && maps/mp/zombies/_zm_equipment::limited_equipment_in_use( self.weaponname ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_ONLY_ONE"; + return 0; + } + if ( player has_player_equipment( self.weaponname ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_HAVE_ONE"; + return 0; + } + /* + if ( getDvarInt( #"1F0A2129" ) ) + { + self.cursor_hint = "HINT_WEAPON"; + self.cursor_hint_weapon = self.weaponname; + } + */ + self.hint_string = self.trigger_hintstring; + } + else if ( self.persistent == 2 ) + { + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.weaponname, undefined ) ) + { + self.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + return 0; + } + else if ( is_true( self.bought ) ) + { + self.hint_string = &"ZOMBIE_GO_TO_THE_BOX"; + return 0; + } + self.hint_string = self.trigger_hintstring; + } + else + { + self.hint_string = ""; + return 0; + } + return 1; +} + +player_continue_building( buildablezone, build_stub ) //checked matches cerberus output +{ + if ( !isDefined( build_stub ) ) + { + build_stub = buildablezone.stub; + } + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || self maps/mp/zombies/_zm_utility::in_revive_trigger() ) + { + return 0; + } + if ( self isthrowinggrenade() ) + { + return 0; + } + if ( !self player_can_build( buildablezone, 1 ) ) + { + return 0; + } + if ( isDefined( self.screecher ) ) + { + return 0; + } + if ( !self usebuttonpressed() ) + { + return 0; + } + slot = build_stub.buildablestruct.buildable_slot; + if ( !buildablezone buildable_is_piece_building( self player_get_buildable_piece( slot ) ) ) + { + return 0; + } + trigger = build_stub maps/mp/zombies/_zm_unitrigger::unitrigger_trigger( self ); + if ( build_stub.script_unitrigger_type == "unitrigger_radius_use" ) + { + torigin = build_stub unitrigger_origin(); + porigin = self geteye(); + radius_sq = 2.25 * build_stub.test_radius_sq; + if ( distance2dsquared( torigin, porigin ) > radius_sq ) + { + return 0; + } + } + else + { + if ( !isDefined( trigger ) || !trigger istouching( self ) ) + { + return 0; + } + } + if ( is_true( build_stub.require_look_at ) && !self is_player_looking_at( trigger.origin, 0.4 ) ) + { + return 0; + } + return 1; +} + +player_progress_bar_update( start_time, build_time ) //checked partially matches cerberus output but order of operations may need to be adjusted +{ + self endon( "entering_last_stand" ); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "buildable_progress_end" ); + while ( isDefined( self ) && ( getTime() - start_time ) < build_time ) + { + progress = ( getTime() - start_time ) / build_time; + if ( progress < 0 ) + { + progress = 0; + } + if ( progress > 1 ) + { + progress = 1; + } + self.usebar updatebar( progress ); + wait 0.05; + } +} + +player_progress_bar( start_time, build_time, building_prompt ) //checked matches cerberus output +{ + self.usebar = self createprimaryprogressbar(); + self.usebartext = self createprimaryprogressbartext(); + if ( isDefined( building_prompt ) ) + { + self.usebartext settext( building_prompt ); + } + else + { + self.usebartext settext( &"ZOMBIE_BUILDING" ); + } + if ( isDefined( self ) && isDefined( start_time ) && isDefined( build_time ) ) + { + self player_progress_bar_update( start_time, build_time ); + } + self.usebartext destroyelem(); + self.usebar destroyelem(); +} + +buildable_use_hold_think_internal( player, bind_stub ) //checked changed to match cerberus output order of operations may need to be checked +{ + if ( !isDefined( bind_stub ) ) + { + bind_stub = self.stub; + } + wait 0.01; + if ( !isDefined( self ) ) + { + self notify( "build_failed" ); + if ( isDefined( player.buildableaudio ) ) + { + player.buildableaudio delete(); + player.buildableaudio = undefined; + } + return; + } + if ( !isDefined( self.usetime ) ) + { + self.usetime = int( 3000 ); + } + self.build_time = self.usetime; + self.build_start_time = getTime(); + build_time = self.build_time; + build_start_time = self.build_start_time; + player disable_player_move_states( 1 ); + player increment_is_drinking(); + orgweapon = player getcurrentweapon(); + build_weapon = "zombie_builder_zm"; + if ( isDefined( bind_stub.build_weapon ) ) + { + build_weapon = bind_stub.build_weapon; + } + player giveweapon( build_weapon ); + player switchtoweapon( build_weapon ); + slot = bind_stub.buildablestruct.buildable_slot; + bind_stub.buildablezone buildable_set_piece_building( player player_get_buildable_piece( slot ) ); + player thread player_progress_bar( build_start_time, build_time, bind_stub.building_prompt ); + if ( isDefined( level.buildable_build_custom_func ) ) + { + player thread [[ level.buildable_build_custom_func ]]( self.stub ); + } + while ( isDefined( self ) && player player_continue_building( bind_stub.buildablezone, self.stub ) && ( getTime() - self.build_start_time ) < self.build_time ) + { + wait 0.05; + } + player notify( "buildable_progress_end" ); + player maps/mp/zombies/_zm_weapons::switch_back_primary_weapon( orgweapon ); + player takeweapon( "zombie_builder_zm" ); + if ( is_true( player.is_drinking ) ) + { + player decrement_is_drinking(); + } + player enable_player_move_states(); + if ( isDefined( self ) && player player_continue_building( bind_stub.buildablezone, self.stub ) && ( getTime() - self.build_start_time ) >= self.build_time ) + { + buildable_clear_piece_building( player player_get_buildable_piece( slot ) ); + self notify( "build_succeed" ); + } + else if ( isDefined( player.buildableaudio ) ) + { + player.buildableaudio delete(); + player.buildableaudio = undefined; + } + buildable_clear_piece_building( player player_get_buildable_piece( slot ) ); + self notify( "build_failed" ); +} + +buildable_play_build_fx( player ) //checked matches cerberus output +{ + self endon( "kill_trigger" ); + self endon( "build_succeed" ); + self endon( "build_failed" ); + while ( 1 ) + { + playfx( level._effect[ "building_dust" ], player getplayercamerapos(), player.angles ); + wait 0.5; + } +} + +buildable_use_hold_think( player, bind_stub ) //checked matches cerberus output +{ + if ( !isDefined( bind_stub ) ) + { + bind_stub = self.stub; + } + self thread buildable_play_build_fx( player ); + self thread buildable_use_hold_think_internal( player, bind_stub ); + retval = self waittill_any_return( "build_succeed", "build_failed" ); + if ( retval == "build_succeed" ) + { + return 1; + } + return 0; +} + +buildable_place_think() //checked partially changed to match cerberus output //changed at own discretion +{ + self endon( "kill_trigger" ); + player_built = undefined; + while ( !is_true( self.stub.built ) ) + { + self waittill( "trigger", player ); + if ( player != self.parent_player ) + { + continue; + } + if ( isDefined( player.screecher_weapon ) ) + { + continue; + } + if ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0.5 ); + } + status = player player_can_build( self.stub.buildablezone ); + if ( !status ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + if ( isDefined( self.stub.oncantuse ) ) + { + self.stub [[ self.stub.oncantuse ]]( player ); + } + //continue; + } + else if ( isDefined( self.stub.onbeginuse ) ) + { + self.stub [[ self.stub.onbeginuse ]]( player ); + } + result = self buildable_use_hold_think( player ); + team = player.pers[ "team" ]; + if ( isDefined( self.stub.onenduse ) ) + { + self.stub [[ self.stub.onenduse ]]( team, player, result ); + } + if ( !result ) + { + continue; + } + if ( isDefined( self.stub.onuse ) ) + { + self.stub [[ self.stub.onuse ]]( player ); + } + slot = self.stub.buildablestruct.buildable_slot; + if ( isDefined( player player_get_buildable_piece( slot ) ) ) + { + prompt = player player_build( self.stub.buildablezone ); + player_built = player; + self.stub.hint_string = prompt; + } + self sethintstring( self.stub.hint_string ); + } + if ( isDefined( player_built ) ) + { + switch( self.stub.persistent ) + { + case 1: + self bptrigger_think_persistent( player_built ); + break; + case 0: + self bptrigger_think_one_time( player_built ); + break; + case 3: + self bptrigger_think_unbuild( player_built ); + break; + case 2: + self bptrigger_think_one_use_and_fly( player_built ); + break; + case 4: + self [[ self.stub.custom_completion_callback ]]( player_built ); + break; + } + } +} + +bptrigger_think_one_time( player_built ) //checked matches cerberus output +{ + self.stub buildablestub_remove(); + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.stub ); +} + +bptrigger_think_unbuild( player_built ) //checked matches cerberus output +{ + stub_unbuild_buildable( self.stub, 1 ); +} + +bptrigger_think_one_use_and_fly( player_built ) //checked changed to match cerberus output +{ + if ( isDefined( player_built ) ) + { + self buildabletrigger_update_prompt( player_built ); + } + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.stub.weaponname, undefined ) ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + self sethintstring( self.stub.hint_string ); + return; + } + if ( is_true( self.stub.bought ) ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX"; + self sethintstring( self.stub.hint_string ); + return; + } + if ( isDefined( self.stub.model ) ) + { + self.stub.model notsolid(); + self.stub.model show(); + } + while ( self.stub.persistent == 2 ) + { + self waittill( "trigger", player ); + if ( isDefined( player.screecher_weapon ) ) + { + continue; + } + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.stub.weaponname, undefined ) ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + self sethintstring( self.stub.hint_string ); + return; + } + if ( !is_true( self.stub.built ) ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + return; + } + if ( player != self.parent_player ) + { + continue; + } + if ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + self.stub.bought = 1; + if ( isDefined( self.stub.model ) ) + { + self.stub.model thread model_fly_away(); + } + player maps/mp/zombies/_zm_weapons::weapon_give( self.stub.weaponname ); + if ( isDefined( level.zombie_include_buildables[ self.stub.equipname ].onbuyweapon ) ) + { + self [[ level.zombie_include_buildables[ self.stub.equipname ].onbuyweapon ]]( player ); + } + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.stub.weaponname, undefined ) ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + } + else + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX"; + } + self sethintstring( self.stub.hint_string ); + player track_buildables_pickedup( self.stub.weaponname ); + } +} + +bptrigger_think_persistent( player_built ) //checked changed to match cerberus output +{ + if ( !isDefined( player_built ) || self [[ self.stub.prompt_and_visibility_func ]]( player_built ) ) + { + if ( isDefined( self.stub.model ) ) + { + self.stub.model notsolid(); + self.stub.model show(); + } + while ( self.stub.persistent == 1 ) + { + self waittill( "trigger", player ); + if ( isDefined( player.screecher_weapon ) ) + { + continue; + } + if ( !is_true( self.stub.built ) ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + self setcursorhint( "HINT_NOICON" ); + return; + } + if ( player != self.parent_player ) + { + continue; + } + if ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0.5 ); + } + if ( player has_player_equipment( self.stub.weaponname ) ) + { + continue; + } + if ( isDefined( self.stub.buildablestruct.onbought ) ) + { + self [[ self.stub.buildablestruct.onbought ]]( player ); + continue; + } + else if ( !maps/mp/zombies/_zm_equipment::is_limited_equipment( self.stub.weaponname ) || !maps/mp/zombies/_zm_equipment::limited_equipment_in_use( self.stub.weaponname ) ) + { + player maps/mp/zombies/_zm_equipment::equipment_buy( self.stub.weaponname ); + player giveweapon( self.stub.weaponname ); + player setweaponammoclip( self.stub.weaponname, 1 ); + if ( isDefined( level.zombie_include_buildables[ self.stub.equipname ].onbuyweapon ) ) + { + self [[ level.zombie_include_buildables[ self.stub.equipname ].onbuyweapon ]]( player ); + } + if ( self.stub.weaponname != "keys_zm" ) + { + player setactionslot( 1, "weapon", self.stub.weaponname ); + } + self.stub.cursor_hint = "HINT_NOICON"; + self.stub.cursor_hint_weapon = undefined; + self setcursorhint( self.stub.cursor_hint ); + if ( isDefined( level.zombie_buildables[ self.stub.equipname ].bought ) ) + { + self.stub.hint_string = level.zombie_buildables[ self.stub.equipname ].bought; + } + else + { + self.stub.hint_string = ""; + } + self sethintstring( self.stub.hint_string ); + player track_buildables_pickedup( self.stub.weaponname ); + } + else + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + self.stub.cursor_hint = "HINT_NOICON"; + self.stub.cursor_hint_weapon = undefined; + self setcursorhint( self.stub.cursor_hint ); + } + } + } +} + +bptrigger_think_unbuild_no_return( player ) //checked matches cerberus output +{ + stub_unbuild_buildable( self.stub, 0 ); +} + +bpstub_set_custom_think_callback( callback ) //checked matches cerberus output +{ + self.persistent = 4; + self.custom_completion_callback = callback; +} + +model_fly_away() //checked changed to match cerberus output +{ + self moveto( self.origin + vectorScale( ( 0, 0, 1 ), 40 ), 3 ); + direction = self.origin; + direction = ( direction[ 1 ], direction[ 0 ], 0 ); + if ( direction[ 1 ] < 0 || direction[ 0 ] > 0 && direction[ 1 ] > 0 ) + { + direction = ( direction[ 0 ], direction[ 1 ] * -1, 0 ); + } + else if ( direction[ 0 ] < 0 ) + { + direction = ( direction[ 0 ] * -1, direction[ 1 ], 0 ); + } + self vibrate( direction, 10, 0.5, 4 ); + self waittill( "movedone" ); + self hide(); + playfx( level._effect[ "poltergeist" ], self.origin ); +} + +find_buildable_stub( equipname ) //checked changed to match cerberus output +{ + foreach ( stub in level.buildable_stubs ) + { + if ( stub.equipname == equipname ) + { + return stub; + } + } + return undefined; +} + +unbuild_buildable( equipname, return_pieces, origin, angles ) //checked matches cerberus output +{ + stub = find_buildable_stub( equipname ); + stub_unbuild_buildable( stub, return_pieces, origin, angles ); +} + +stub_unbuild_buildable( stub, return_pieces, origin, angles ) //checked partially changed to match cerberus output //did not change while loop to for loop +{ + if ( isDefined( stub ) ) + { + buildable = stub.buildablezone; + buildable.built = 0; + buildable.stub.built = 0; + buildable notify( "unbuilt" ); + level.buildables_built[ buildable.buildable_name ] = 0; + level notify( buildable.buildable_name + "_unbuilt" ); + i = 0; + while ( i < buildable.pieces.size ) + { + buildable.pieces[ i ].built = 0; + if ( isDefined( buildable.pieces[ i ].part_name ) ) + { + buildable.stub.model notsolid(); + if ( is_true( buildable.pieces[ i ].built ) ) + { + buildable.stub.model hidepart( buildable.pieces[ i ].part_name ); + } + else + { + buildable.stub.model show(); + buildable.stub.model showpart( buildable.pieces[ i ].part_name ); + } + } + if ( is_true( return_pieces ) ) + { + if ( isDefined( buildable.stub.str_unbuild_notify ) ) + { + buildable.pieces[ i ] thread piece_spawn_at_with_notify_delay( origin, angles, buildable.stub.str_unbuild_notify, buildable.stub.unbuild_respawn_fn ); + i++; + continue; + } + buildable.pieces[ i ] piece_spawn_at( origin, angles ); + } + i++; + } + if ( isDefined( buildable.stub.model ) ) + { + buildable.stub.model hide(); + } + } +} + +player_explode_buildable( equipname, origin, speed, return_to_spawn, return_time ) //checked changed to match cerberus output +{ + self explosiondamage( 50, origin ); + stub = find_buildable_stub( equipname ); + if ( isDefined( stub ) ) + { + buildable = stub.buildablezone; + buildable.built = 0; + buildable.stub.built = 0; + buildable notify( "unbuilt" ); + level.buildables_built[ buildable.buildable_name ] = 0; + level notify( buildable.buildable_name + "_unbuilt" ); + for ( i = 0; i < buildable.pieces.size; i++ ) + { + buildable.pieces[ i ].built = 0; + if ( isDefined( buildable.pieces[ i ].part_name ) ) + { + buildable.stub.model notsolid(); + if ( !is_true( buildable.pieces[ i ].built ) ) + { + buildable.stub.model hidepart( buildable.pieces[ i ].part_name ); + } + else + { + buildable.stub.model show(); + buildable.stub.model showpart( buildable.pieces[ i ].part_name ); + } + } + ang = randomfloat( 360 ); + h = 0.25 + randomfloat( 0.5 ); + dir = ( sin( ang ), cos( ang ), h ); + self thread player_throw_piece( buildable.pieces[ i ], origin, speed * dir, return_to_spawn, return_time ); + } + buildable.stub.model hide(); + } +} + +think_buildables() //checked changed to match cerberus output +{ + foreach ( buildable in level.zombie_include_buildables ) + { + if ( isDefined( buildable.triggerthink ) ) + { + level [[ buildable.triggerthink ]](); + wait_network_frame(); + } + } + level notify( "buildables_setup" ); +} + +buildable_trigger_think( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) //checked matches cerberus output +{ + return setup_unitrigger_buildable( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +buildable_trigger_think_array( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) //checked matches cerberus output +{ + return setup_unitrigger_buildable_array( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +buildable_set_unbuild_notify_delay( str_equipname, str_unbuild_notify, unbuild_respawn_fn ) //checked matches cerberus output +{ + stub = find_buildable_stub( str_equipname ); + stub.str_unbuild_notify = str_unbuild_notify; + stub.unbuild_respawn_fn = unbuild_respawn_fn; +} + +setup_vehicle_unitrigger_buildable( parent, trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) //checked matches cerberus output +{ + trig = getent( trigger_targetname, "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.buildablestruct = level.zombie_include_buildables[ equipname ]; + unitrigger_stub.link_parent = parent; + unitrigger_stub.origin_parent = trig; + unitrigger_stub.trigger_targetname = trigger_targetname; + unitrigger_stub.originfunc = ::anystub_get_unitrigger_origin; + unitrigger_stub.onspawnfunc = ::anystub_on_spawn_trigger; + unitrigger_stub.origin = trig.origin; + unitrigger_stub.angles = trig.angles; + unitrigger_stub.equipname = equipname; + unitrigger_stub.weaponname = weaponname; + unitrigger_stub.trigger_hintstring = trigger_hintstring; + unitrigger_stub.delete_trigger = delete_trigger; + unitrigger_stub.built = 0; + unitrigger_stub.persistent = persistent; + unitrigger_stub.usetime = int( 3000 ); + unitrigger_stub.onbeginuse = ::onbeginuseuts; + unitrigger_stub.onenduse = ::onenduseuts; + unitrigger_stub.onuse = ::onuseplantobjectuts; + unitrigger_stub.oncantuse = ::oncantuseuts; + if ( isDefined( trig.script_length ) ) + { + unitrigger_stub.script_length = trig.script_length; + } + else + { + unitrigger_stub.script_length = 24; + } + if ( isDefined( trig.script_width ) ) + { + unitrigger_stub.script_width = trig.script_width; + } + else + { + unitrigger_stub.script_width = 64; + } + if ( isDefined( trig.script_height ) ) + { + unitrigger_stub.script_height = trig.script_height; + } + else + { + unitrigger_stub.script_height = 24; + } + if ( isDefined( trig.radius ) ) + { + unitrigger_stub.radius = trig.radius; + } + else + { + unitrigger_stub.radius = 64; + } + unitrigger_stub.target = trig.target; + unitrigger_stub.targetname = trig.targetname + "_trigger"; + unitrigger_stub.script_noteworthy = trig.script_noteworthy; + unitrigger_stub.script_parameters = trig.script_parameters; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + if ( isDefined( level.zombie_buildables[ equipname ].hint ) ) + { + unitrigger_stub.hint_string = level.zombie_buildables[ equipname ].hint; + } + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + unitrigger_stub.require_look_at = 1; + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + unitrigger_stub.prompt_and_visibility_func = ::buildabletrigger_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_unitrigger( unitrigger_stub, ::buildable_place_think ); + unitrigger_stub.piece_trigger = trig; + trig.trigger_stub = unitrigger_stub; + unitrigger_stub.buildablezone = unitrigger_stub buildable_piece_unitriggers( equipname, unitrigger_stub.origin ); + if ( delete_trigger ) + { + trig delete(); + } + level.buildable_stubs[ level.buildable_stubs.size ] = unitrigger_stub; + return unitrigger_stub; +} + +vehicle_buildable_trigger_think( vehicle, trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) //checked matches cerberus output +{ + return setup_vehicle_unitrigger_buildable( vehicle, trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +ai_buildable_trigger_think( parent, equipname, weaponname, trigger_hintstring, persistent ) //checked matches cerberus output +{ + unitrigger_stub = spawnstruct(); + unitrigger_stub.buildablestruct = level.zombie_include_buildables[ equipname ]; + unitrigger_stub.link_parent = parent; + unitrigger_stub.origin_parent = parent; + unitrigger_stub.originfunc = ::anystub_get_unitrigger_origin; + unitrigger_stub.onspawnfunc = ::anystub_on_spawn_trigger; + unitrigger_stub.origin = parent.origin; + unitrigger_stub.angles = parent.angles; + unitrigger_stub.equipname = equipname; + unitrigger_stub.weaponname = weaponname; + unitrigger_stub.trigger_hintstring = trigger_hintstring; + unitrigger_stub.delete_trigger = 1; + unitrigger_stub.built = 0; + unitrigger_stub.persistent = persistent; + unitrigger_stub.usetime = int( 3000 ); + unitrigger_stub.onbeginuse = ::onbeginuseuts; + unitrigger_stub.onenduse = ::onenduseuts; + unitrigger_stub.onuse = ::onuseplantobjectuts; + unitrigger_stub.oncantuse = ::oncantuseuts; + unitrigger_stub.script_length = 64; + unitrigger_stub.script_width = 64; + unitrigger_stub.script_height = 54; + unitrigger_stub.radius = 64; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + if ( isDefined( level.zombie_buildables[ equipname ].hint ) ) + { + unitrigger_stub.hint_string = level.zombie_buildables[ equipname ].hint; + } + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + unitrigger_stub.require_look_at = 0; + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + unitrigger_stub.prompt_and_visibility_func = ::buildabletrigger_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_unitrigger( unitrigger_stub, ::buildable_place_think ); + unitrigger_stub.buildablezone = unitrigger_stub buildable_piece_unitriggers( equipname, unitrigger_stub.origin ); + level.buildable_stubs[ level.buildable_stubs.size ] = unitrigger_stub; + return unitrigger_stub; +} + +onpickuputs( player ) //checked matches cerberus output +{ + /* +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Buildable piece recovered by - " + player.name ); +#/ + } + */ +} + +ondroputs( player ) //checked matches cerberus output +{ + /* +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Buildable piece dropped by - " + player.name ); +#/ + } + */ + player notify( "event_ended" ); +} + +onbeginuseuts( player ) //checked matches cerberus output +{ + /* +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Buildable piece begin use by - " + player.name ); +#/ + } + */ + if ( isDefined( self.buildablestruct.onbeginuse ) ) + { + self [[ self.buildablestruct.onbeginuse ]]( player ); + } + if ( isDefined( player ) && !isDefined( player.buildableaudio ) ) + { + alias = sndbuildableusealias( self.targetname ); + player.buildableaudio = spawn( "script_origin", player.origin ); + player.buildableaudio playloopsound( alias ); + } +} + +sndbuildableusealias( name ) //checked matches cerberus output +{ + alias = undefined; + switch( name ) + { + case "cell_door_trigger": + alias = "zmb_jail_buildable"; + break; + case "generator_use_trigger": + alias = "zmb_generator_buildable"; + break; + case "chalk_buildable_trigger": + alias = "zmb_chalk_loop"; + break; + default: + alias = "zmb_buildable_loop"; + break; + } + return alias; +} + +onenduseuts( team, player, result ) //checked matches cerberus output +{ + /* +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Buildable piece end use by - " + player.name ); +#/ + } + */ + if ( !isDefined( player ) ) + { + return; + } + if ( isDefined( player.buildableaudio ) ) + { + player.buildableaudio delete(); + player.buildableaudio = undefined; + } + if ( isDefined( self.buildablestruct.onenduse ) ) + { + self [[ self.buildablestruct.onenduse ]]( team, player, result ); + } + player notify( "event_ended" ); +} + +oncantuseuts( player ) //checked matches cerberus output +{ + /* +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Buildable piece can't use by - " + player.name ); +#/ + } + */ + if ( isDefined( self.buildablestruct.oncantuse ) ) + { + self [[ self.buildablestruct.oncantuse ]]( player ); + } +} + +onuseplantobjectuts( player ) //checked matches cerberus output +{ + /* +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Buildable piece crafted by - " + player.name ); +#/ + } + */ + if ( isDefined( self.buildablestruct.onuseplantobject ) ) + { + self [[ self.buildablestruct.onuseplantobject ]]( player ); + } + player notify( "bomb_planted" ); +} + +add_zombie_buildable_vox_category( buildable_name, vox_id ) //checked matches cerberus output +{ + buildable_struct = level.zombie_include_buildables[ buildable_name ]; + buildable_struct.vox_id = vox_id; +} + +add_zombie_buildable_piece_vox_category( buildable_name, vox_id, timer ) //checked matches cerberus output +{ + buildable_struct = level.zombie_include_buildables[ buildable_name ]; + buildable_struct.piece_vox_id = vox_id; + buildable_struct.piece_vox_timer = timer; +} + +is_buildable() //checked matches cerberus output +{ + if ( !isDefined( level.zombie_buildables ) ) + { + return 0; + } + if ( isDefined( self.zombie_weapon_upgrade ) && isDefined( level.zombie_buildables[ self.zombie_weapon_upgrade ] ) ) + { + return 1; + } + if ( isDefined( self.script_noteworthy ) && self.script_noteworthy == "specialty_weapupgrade" ) + { + if ( isDefined( level.buildables_built[ "pap" ] ) && level.buildables_built[ "pap" ] ) + { + return 0; + } + return 1; + } + return 0; +} + +buildable_crafted() //checked matches cerberus output +{ + self.pieces--; + +} + +buildable_complete() //checked matches cerberus output +{ + if ( self.pieces <= 0 ) + { + return 1; + } + return 0; +} + +get_buildable_hint( buildable_name ) //checked matches cerberus output +{ + /* +/# + assert( isDefined( level.zombie_buildables[ buildable_name ] ), buildable_name + " was not included or is not part of the zombie weapon list." ); +#/ + */ + return level.zombie_buildables[ buildable_name ].hint; +} + +delete_on_disconnect( buildable, self_notify, skip_delete ) //checked matches cerberus output +{ + buildable endon( "death" ); + self waittill( "disconnect" ); + if ( isDefined( self_notify ) ) + { + self notify( self_notify ); + } + if ( isDefined( skip_delete ) && !skip_delete ) + { + if ( isDefined( buildable.stub ) ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( buildable.stub ); + buildable.stub = undefined; + } + if ( isDefined( buildable ) ) + { + buildable delete(); + } + } +} + +get_buildable_pickup( buildablename, modelname ) //checked changed to match cerberus output +{ + foreach ( buildablepickup in level.buildablepickups ) + { + if ( buildablepickup[ 0 ].buildablestruct.name == buildablename && buildablepickup[ 0 ].visuals[ 0 ].model == modelname ) + { + return buildablepickup[ 0 ]; + } + } + return undefined; +} + +track_buildable_piece_pickedup( piece ) //checked matches cerberus output +{ + if ( !isDefined( piece ) || !isDefined( piece.buildablename ) ) + { + /* +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_buildable_piece_pickedup() \n" ); +#/ + */ + return; + } + self add_map_buildable_stat( piece.buildablename, "pieces_pickedup", 1 ); + buildable_struct = level.zombie_include_buildables[ piece.buildablename ]; + if ( isDefined( buildable_struct.piece_vox_id ) ) + { + if ( isDefined( self.a_buildable_piece_pickedup_vox_cooldown ) && isinarray( self.a_buildable_piece_pickedup_vox_cooldown, buildable_struct.piece_vox_id ) ) + { + return; + } + self thread do_player_general_vox( "general", buildable_struct.piece_vox_id + "_pickup" ); + if ( isDefined( buildable_struct.piece_vox_timer ) ) + { + self thread buildable_piece_pickedup_vox_cooldown( buildable_struct.piece_vox_id, buildable_struct.piece_vox_timer ); + } + } + else + { + self thread do_player_general_vox( "general", "build_pickup" ); + } +} + +buildable_piece_pickedup_vox_cooldown( piece_vox_id, timer ) //checked matches cerberus output +{ + self endon( "disconnect" ); + if ( !isDefined( self.a_buildable_piece_pickedup_vox_cooldown ) ) + { + self.a_buildable_piece_pickedup_vox_cooldown = []; + } + self.a_buildable_piece_pickedup_vox_cooldown[ self.a_buildable_piece_pickedup_vox_cooldown.size ] = piece_vox_id; + wait timer; + arrayremovevalue( self.a_buildable_piece_pickedup_vox_cooldown, piece_vox_id ); +} + +track_buildable_pieces_built( buildable ) //checked matches cerberus output +{ + if ( !isDefined( buildable ) || !isDefined( buildable.buildable_name ) ) + { + /* +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_buildable_pieces_built() \n" ); +#/ + */ + return; + } + bname = buildable.buildable_name; + if ( isDefined( buildable.stat_name ) ) + { + bname = buildable.stat_name; + } + self add_map_buildable_stat( bname, "pieces_built", 1 ); + if ( !buildable buildable_all_built() ) + { + if ( isDefined( level.zombie_include_buildables[ buildable.buildable_name ] ) && isDefined( level.zombie_include_buildables[ buildable.buildable_name ].snd_build_add_vo_override ) ) + { + self thread [[ level.zombie_include_buildables[ buildable.buildable_name ].snd_build_add_vo_override ]](); + return; + } + else + { + self thread do_player_general_vox( "general", "build_add" ); + } + } +} + +track_buildables_built( buildable ) //checked matches cerberus output +{ + if ( !isDefined( buildable ) || !isDefined( buildable.buildable_name ) ) + { + /* +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_buildables_built() \n" ); +#/ + */ + return; + } + bname = buildable.buildable_name; + if ( isDefined( buildable.stat_name ) ) + { + bname = buildable.stat_name; + } + self add_map_buildable_stat( bname, "buildable_built", 1 ); + self maps/mp/zombies/_zm_stats::increment_client_stat( "buildables_built", 0 ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "buildables_built" ); + if ( isDefined( buildable.stub.buildablestruct.vox_id ) ) + { + self thread do_player_general_vox( "general", "build_" + buildable.stub.buildablestruct.vox_id + "_final" ); + } +} + +track_buildables_pickedup( buildable ) //checked matches cerberus output +{ + if ( !isDefined( buildable ) ) + { + /* +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_buildables_pickedup() \n" ); +#/ + */ + return; + } + stat_name = get_buildable_stat_name( buildable ); + if ( !isDefined( stat_name ) ) + { + /* +/# + println( "STAT TRACKING FAILURE: NO STAT NAME FOR " + buildable + "\n" ); +#/ + */ + return; + } + self add_map_buildable_stat( stat_name, "buildable_pickedup", 1 ); + self say_pickup_buildable_vo( buildable, 0 ); +} + +track_buildables_planted( equipment ) //checked matches cerberus output +{ + if ( !isDefined( equipment ) ) + { + /* +/# + println( "STAT TRACKING FAILURE: NOT DEFINED for track_buildables_planted() \n" ); +#/ + */ + return; + } + buildable_name = undefined; + if ( isDefined( equipment.name ) ) + { + buildable_name = get_buildable_stat_name( equipment.name ); + } + if ( !isDefined( buildable_name ) ) + { + /* +/# + println( "STAT TRACKING FAILURE: NO BUILDABLE NAME FOR track_buildables_planted() " + equipment.name + "\n" ); +#/ + */ + return; + } + maps/mp/_demo::bookmark( "zm_player_buildable_placed", getTime(), self ); + self add_map_buildable_stat( buildable_name, "buildable_placed", 1 ); + vo_name = "build_plc_" + buildable_name; + if ( buildable_name == "electric_trap" ) + { + vo_name = "build_plc_trap"; + } + if ( !is_true( self.buildable_timer ) ) + { + self thread do_player_general_vox( "general", vo_name ); + self thread placed_buildable_vo_timer(); + } +} + +placed_buildable_vo_timer() //checked matches cerberus output +{ + self endon( "disconnect" ); + self.buildable_timer = 1; + wait 60; + self.buildable_timer = 0; +} + +buildable_pickedup_timer() //checked matches cerberus output +{ + self endon( "disconnect" ); + self.buildable_pickedup_timer = 1; + wait 60; + self.buildable_pickedup_timer = 0; +} + +track_planted_buildables_pickedup( equipment ) //checked changed to match cerberus output +{ + if ( !isDefined( equipment ) ) + { + return; + } + if ( equipment == "equip_turbine_zm" || equipment == "equip_turret_zm" || equipment == "equip_electrictrap_zm" || equipment == "riotshield_zm" ) + { + self maps/mp/zombies/_zm_stats::increment_client_stat( "planted_buildables_pickedup", 0 ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "planted_buildables_pickedup" ); + } + if ( !is_true( self.buildable_pickedup_timer ) ) + { + self say_pickup_buildable_vo( equipment, 1 ); + self thread buildable_pickedup_timer(); + } +} + +track_placed_buildables( buildable_name ) //checked matches cerberus output +{ + if ( !isDefined( buildable_name ) ) + { + return; + } + self add_map_buildable_stat( buildable_name, "buildable_placed", 1 ); + vo_name = undefined; + if ( buildable_name == level.riotshield_name ) + { + vo_name = "build_plc_shield"; + } + if ( !isDefined( vo_name ) ) + { + return; + } + self thread do_player_general_vox( "general", vo_name ); +} + +add_map_buildable_stat( piece_name, stat_name, value ) //checked changed to match cerberus output +{ + if ( isDefined( piece_name ) || piece_name == "sq_common" || piece_name == "keys_zm" || piece_name == "oillamp_zm" ) + { + return; + } + if ( is_true( level.zm_disable_recording_stats ) || is_true( level.zm_disable_recording_buildable_stats ) ) + { + return; + } + self adddstat( "buildables", piece_name, stat_name, value ); +} + +say_pickup_buildable_vo( buildable_name, world ) //checked matches cerberus output +{ + if ( is_true( self.buildable_pickedup_timer ) ) + { + return; + } + name = get_buildable_vo_name( buildable_name ); + if ( !isDefined( name ) ) + { + return; + } + vo_name = "build_pck_b" + name; + if ( is_true( world ) ) + { + vo_name = "build_pck_w" + name; + } + if ( !isDefined( level.transit_buildable_vo_override ) || !( self [[ level.transit_buildable_vo_override ]]( name, world ) ) ) + { + self thread do_player_general_vox( "general", vo_name ); + self thread buildable_pickedup_timer(); + } +} + +get_buildable_vo_name( buildable_name ) //checked matches cerberus output +{ + switch( buildable_name ) + { + case "equip_turbine_zm": + return "turbine"; + case "equip_turret_zm": + return "turret"; + case "equip_electrictrap_zm": + return "trap"; + case "riotshield_zm": + return "shield"; + case "jetgun_zm": + return "jetgun"; + case "equip_springpad_zm": + return "springpad_zm"; + case "equip_slipgun_zm": + return "slipgun_zm"; + case "equip_headchopper_zm": + return "headchopper_zm"; + case "equip_subwoofer_zm": + return "subwoofer_zm"; + } + return undefined; +} + +get_buildable_stat_name( buildable ) //checked matches cerberus output +{ + if ( isDefined( buildable ) ) + { + switch( buildable ) + { + case "equip_turbine_zm": + return "turbine"; + case "equip_turret_zm": + return "turret"; + case "equip_electrictrap_zm": + return "electric_trap"; + case "equip_springpad_zm": + return "springpad_zm"; + case "equip_slipgun_zm": + return "slipgun_zm"; + case "equip_headchopper_zm": + return "headchopper_zm"; + case "equip_subwoofer_zm": + return "subwoofer_zm"; + } + return undefined; + } +} + + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_chugabud.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_chugabud.gsc new file mode 100644 index 0000000..1cf928d --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_chugabud.gsc @@ -0,0 +1,805 @@ +#include maps/mp/_visionset_mgr; +#include maps/mp/zombies/_zm; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_weap_cymbal_monkey; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_clone; +#include maps/mp/zombies/_zm_chugabud; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; +#include maps/mp/zombies/_zm_perks; + +init() //checked matches cerberus output +{ + level.chugabud_laststand_func = ::chugabud_laststand; + level thread chugabud_hostmigration(); + level._effect[ "chugabud_revive_fx" ] = loadfx( "weapon/quantum_bomb/fx_player_position_effect" ); + level._effect[ "chugabud_bleedout_fx" ] = loadfx( "weapon/quantum_bomb/fx_player_position_effect" ); + add_custom_limited_weapon_check( ::is_weapon_available_in_chugabud_corpse ); +} + +chugabug_precache() //checked matches cerberus output +{ +} + +chugabud_player_init() //checked matches cerberus output +{ +} + +chugabud_laststand() //checked changed to match cerberus output +{ + self endon( "player_suicide" ); + self endon( "disconnect" ); + self endon( "chugabud_bleedout" ); + self maps/mp/zombies/_zm_laststand::increment_downed_stat(); + self.ignore_insta_kill = 1; + self.health = self.maxhealth; + self maps/mp/zombies/_zm_chugabud::chugabud_save_loadout(); + self maps/mp/zombies/_zm_chugabud::chugabud_fake_death(); + wait 3; + if ( is_true( self.insta_killed ) || isDefined( self.disable_chugabud_corpse ) ) + { + create_corpse = 0; + } + else + { + create_corpse = 1; + } + if ( create_corpse == 1 ) + { + if ( isDefined( level._chugabug_reject_corpse_override_func ) ) + { + reject_corpse = self [[ level._chugabug_reject_corpse_override_func ]]( self.origin ); + if ( reject_corpse ) + { + create_corpse = 0; + } + } + } + if ( create_corpse == 1 ) + { + self thread activate_chugabud_effects_and_audio(); + corpse = self chugabud_spawn_corpse(); + corpse thread chugabud_corpse_revive_icon( self ); + self.e_chugabud_corpse = corpse; + corpse thread chugabud_corpse_cleanup_on_spectator( self ); + if ( isDefined( level.whos_who_client_setup ) ) + { + corpse setclientfield( "clientfield_whos_who_clone_glow_shader", 1 ); + } + } + self chugabud_fake_revive(); + wait 0.1; + self.ignore_insta_kill = undefined; + self.disable_chugabud_corpse = undefined; + if ( create_corpse == 0 ) + { + self notify( "chugabud_effects_cleanup" ); + return; + } + bleedout_time = getDvarFloat( "player_lastStandBleedoutTime" ); + self thread chugabud_bleed_timeout( bleedout_time, corpse ); + self thread chugabud_handle_multiple_instances( corpse ); + corpse waittill( "player_revived", e_reviver ); + if ( isDefined( e_reviver ) && e_reviver == self ) + { + self notify( "whos_who_self_revive" ); + } + self perk_abort_drinking( 0.1 ); + self maps/mp/zombies/_zm_perks::perk_set_max_health_if_jugg( "health_reboot", 1, 0 ); + self setorigin( corpse.origin ); + self setplayerangles( corpse.angles ); + if ( self player_is_in_laststand() ) + { + self thread chugabud_laststand_cleanup( corpse, "player_revived" ); + self enableweaponcycling(); + self enableoffhandweapons(); + self auto_revive( self, 1 ); + return; + } + self chugabud_laststand_cleanup( corpse, undefined ); +} + +chugabud_laststand_cleanup( corpse, str_notify ) //checked matches cerberus output +{ + if ( isDefined( str_notify ) ) + { + self waittill( str_notify ); + } + self chugabud_give_loadout(); + self chugabud_corpse_cleanup( corpse, 1 ); +} + +chugabud_bleed_timeout( delay, corpse ) //checked changed to match cerberus output +{ + self endon( "player_suicide" ); + self endon( "disconnect" ); + corpse endon( "death" ); + wait delay; + if ( isDefined( corpse.revivetrigger ) ) + { + while ( corpse.revivetrigger.beingrevived ) + { + wait 0.01; + } + } + if ( isDefined( self.loadout.perks ) && flag( "solo_game" ) ) + { + for ( i = 0; i < self.loadout.perks.size; i++ ) + { + perk = self.loadout.perks[ i ]; + if ( perk == "specialty_quickrevive" ) + { + arrayremovevalue( self.loadout.perks, self.loadout.perks[ i ] ); + corpse notify( "player_revived" ); + return; + } + } + } + self chugabud_corpse_cleanup( corpse, 0 ); +} + +chugabud_corpse_cleanup( corpse, was_revived ) //checked matches cerberus output +{ + self notify( "chugabud_effects_cleanup" ); + if ( was_revived ) + { + playsoundatposition( "evt_ww_appear", corpse.origin ); + playfx( level._effect[ "chugabud_revive_fx" ], corpse.origin ); + } + else + { + playsoundatposition( "evt_ww_disappear", corpse.origin ); + playfx( level._effect[ "chugabud_bleedout_fx" ], corpse.origin ); + self notify( "chugabud_bleedout" ); + } + if ( isDefined( corpse.revivetrigger ) ) + { + corpse notify( "stop_revive_trigger" ); + corpse.revivetrigger delete(); + corpse.revivetrigger = undefined; + } + if ( isDefined( corpse.revive_hud_elem ) ) + { + corpse.revive_hud_elem destroy(); + corpse.revive_hud_elem = undefined; + } + self.loadout = undefined; + wait 0.1; + corpse delete(); + self.e_chugabud_corpse = undefined; +} + +chugabud_handle_multiple_instances( corpse ) //checked matches cerberus output +{ + corpse endon( "death" ); + self waittill( "perk_chugabud_activated" ); + self chugabud_corpse_cleanup( corpse, 0 ); +} + +chugabud_spawn_corpse() //checked matches cerberus output +{ + corpse = maps/mp/zombies/_zm_clone::spawn_player_clone( self, self.origin, undefined, self.whos_who_shader ); + corpse.angles = self.angles; + corpse maps/mp/zombies/_zm_clone::clone_give_weapon( "m1911_zm" ); + corpse maps/mp/zombies/_zm_clone::clone_animate( "laststand" ); + corpse.revive_hud = self chugabud_revive_hud_create(); + corpse thread maps/mp/zombies/_zm_laststand::revive_trigger_spawn(); + return corpse; +} + +chugabud_revive_hud_create() //checked matches cerberus output +{ + self.revive_hud = newclienthudelem( self ); + self.revive_hud.alignx = "center"; + self.revive_hud.aligny = "middle"; + self.revive_hud.horzalign = "center"; + self.revive_hud.vertalign = "bottom"; + self.revive_hud.y = -50; + self.revive_hud.foreground = 1; + self.revive_hud.font = "default"; + self.revive_hud.fontscale = 1.5; + self.revive_hud.alpha = 0; + self.revive_hud.color = ( 1, 1, 1 ); + self.revive_hud settext( "" ); + return self.revive_hud; +} + +chugabud_save_loadout() //checked changed to match cerberus output +{ + primaries = self getweaponslistprimaries(); + currentweapon = self getcurrentweapon(); + self.loadout = spawnstruct(); + self.loadout.player = self; + self.loadout.weapons = []; + self.loadout.score = self.score; + self.loadout.current_weapon = -1; + index = 0; + foreach ( weapon in primaries ) + { + logline1 = "weapon: " + weapon + "\n"; + logprint( logline1 ); + self.loadout.weapons[ index ] = maps/mp/zombies/_zm_weapons::get_player_weapondata( self, weapon ); + if ( weapon == currentweapon || self.loadout.weapons[ index ][ "alt_name" ] == currentweapon ) + { + self.loadout.current_weapon = index; + } + index++; + } + self.loadout.equipment = self get_player_equipment(); + if ( isDefined( self.loadout.equipment ) ) + { + self equipment_take( self.loadout.equipment ); + } + self.loadout save_weapons_for_chugabud( self ); + if ( self hasweapon( "claymore_zm" ) ) + { + self.loadout.hasclaymore = 1; + self.loadout.claymoreclip = self getweaponammoclip( "claymore_zm" ); + } + self.loadout.perks = chugabud_save_perks( self ); + self chugabud_save_grenades(); + if ( maps/mp/zombies/_zm_weap_cymbal_monkey::cymbal_monkey_exists() ) + { + self.loadout.zombie_cymbal_monkey_count = self getweaponammoclip( "cymbal_monkey_zm" ); + } +} + +chugabud_save_grenades() //checked matches cerberus output +{ + if ( self hasweapon( "emp_grenade_zm" ) ) + { + self.loadout.hasemp = 1; + self.loadout.empclip = self getweaponammoclip( "emp_grenade_zm" ); + } + lethal_grenade = self get_player_lethal_grenade(); + if ( self hasweapon( lethal_grenade ) ) + { + self.loadout.lethal_grenade = lethal_grenade; + self.loadout.lethal_grenade_count = self getweaponammoclip( lethal_grenade ); + } + else + { + self.loadout.lethal_grenade = undefined; + } +} + +chugabud_give_loadout() //checked partially changed to match cerberus output continues in for loops bad see the github for more info +{ + self takeallweapons(); + loadout = self.loadout; + primaries = self getweaponslistprimaries(); + if ( loadout.weapons.size > 1 || primaries.size > 1 ) + { + foreach ( weapon in primaries ) + { + self takeweapon( weapon ); + } + } + i = 0; + while ( i < loadout.weapons.size ) + { + logline1 = "loadout.weapons[ " + i + " ][ name ] " + loadout.weapons[ i ][ "name" ] + "\n"; + logprint( logline1 ); + if ( !isDefined( loadout.weapons[ i ] ) ) + { + i++; + continue; + } + if ( loadout.weapons[ i ][ "name" ] == "none" ) + { + i++; + continue; + } + self maps/mp/zombies/_zm_weapons::weapondata_give( loadout.weapons[ i ] ); + i++; + } + if ( loadout.current_weapon >= 0 && isDefined( loadout.weapons[ loadout.current_weapon ][ "name" ] ) ) + { + self switchtoweapon( loadout.weapons[ loadout.current_weapon ][ "name" ] ); + } + self giveweapon( "knife_zm" ); + self maps/mp/zombies/_zm_equipment::equipment_give( self.loadout.equipment ); + loadout restore_weapons_for_chugabud( self ); + self chugabud_restore_claymore(); + self.score = loadout.score; + self.pers[ "score" ] = loadout.score; + perk_array = maps/mp/zombies/_zm_perks::get_perk_array( 1 ); + for ( i = 0; i < perk_array.size; i++ ) + { + perk = perk_array[ i ]; + self unsetperk( perk ); + self.num_perks--; + self set_perk_clientfield( perk, 0 ); + } + if ( isDefined( loadout.perks ) && loadout.perks.size > 0 ) + { + i = 0; + while ( i < loadout.perks.size ) + { + if ( self hasperk( loadout.perks[ i ] ) ) + { + i++; + continue; + } + if ( loadout.perks[ i ] == "specialty_quickrevive" && flag( "solo_game" ) ) + { + level.solo_game_free_player_quickrevive = 1; + } + if ( loadout.perks[ i ] == "specialty_finalstand" ) + { + i++; + continue; + } + maps/mp/zombies/_zm_perks::give_perk( loadout.perks[ i ] ); + i++; + } + } + self chugabud_restore_grenades(); + if ( maps/mp/zombies/_zm_weap_cymbal_monkey::cymbal_monkey_exists() ) + { + if ( loadout.zombie_cymbal_monkey_count ) + { + self maps/mp/zombies/_zm_weap_cymbal_monkey::player_give_cymbal_monkey(); + self setweaponammoclip( "cymbal_monkey_zm", loadout.zombie_cymbal_monkey_count ); + } + } +} + +chugabud_restore_grenades() //checked matches cerberus output +{ + if ( is_true( self.loadout.hasemp ) ) + { + self giveweapon( "emp_grenade_zm" ); + self setweaponammoclip( "emp_grenade_zm", self.loadout.empclip ); + } + if ( isDefined( self.loadout.lethal_grenade ) ) + { + self giveweapon( self.loadout.lethal_grenade ); + self setweaponammoclip( self.loadout.lethal_grenade, self.loadout.lethal_grenade_count ); + } +} + +chugabud_restore_claymore() //checked matches cerberus output +{ + if ( is_true( self.loadout.hasclaymore ) && !self hasweapon( "claymore_zm" ) ) + { + self giveweapon( "claymore_zm" ); + self set_player_placeable_mine( "claymore_zm" ); + self setactionslot( 4, "weapon", "claymore_zm" ); + self setweaponammoclip( "claymore_zm", self.loadout.claymoreclip ); + } +} + +chugabud_fake_death() //checked matches cerberus output +{ + level notify( "fake_death" ); + self notify( "fake_death" ); + self takeallweapons(); + self allowstand( 0 ); + self allowcrouch( 0 ); + self allowprone( 1 ); + self.ignoreme = 1; + self enableinvulnerability(); + wait 0.1; + self freezecontrols( 1 ); + wait 0.9; +} + +chugabud_fake_revive() //checked matches cerberus output +{ + level notify( "fake_revive" ); + self notify( "fake_revive" ); + playsoundatposition( "evt_ww_disappear", self.origin ); + playfx( level._effect[ "chugabud_revive_fx" ], self.origin ); + spawnpoint = chugabud_get_spawnpoint(); + if ( isDefined( level._chugabud_post_respawn_override_func ) ) + { + self [[ level._chugabud_post_respawn_override_func ]]( spawnpoint.origin ); + } + if ( isDefined( level.chugabud_force_corpse_position ) ) + { + if ( isDefined( self.e_chugabud_corpse ) ) + { + self.e_chugabud_corpse forceteleport( level.chugabud_force_corpse_position ); + } + level.chugabud_force_corpse_position = undefined; + } + if ( isDefined( level.chugabud_force_player_position ) ) + { + spawnpoint.origin = level.chugabud_force_player_position; + level.chugabud_force_player_position = undefined; + } + self setorigin( spawnpoint.origin ); + self setplayerangles( spawnpoint.angles ); + playsoundatposition( "evt_ww_appear", spawnpoint.origin ); + playfx( level._effect[ "chugabud_revive_fx" ], spawnpoint.origin ); + self allowstand( 1 ); + self allowcrouch( 1 ); + self allowprone( 1 ); + self.ignoreme = 0; + self setstance( "stand" ); + self freezecontrols( 0 ); + self giveweapon( "knife_zm" ); + self give_start_weapon( 1 ); + self.score = self.loadout.score; + self.pers[ "score" ] = self.loadout.score; + self giveweapon( "frag_grenade_zm" ); + self setweaponammoclip( "frag_grenade_zm", 2 ); + self chugabud_restore_claymore(); + wait 1; + self disableinvulnerability(); +} + +chugabud_get_spawnpoint() //checked partially changed to match cerberus output nested foreach is probably bad +{ + spawnpoint = undefined; + if ( get_chugabug_spawn_point_from_nodes( self.origin, 500, 700, 64, 1 ) ) + { + spawnpoint = level.chugabud_spawn_struct; + } + if ( !isDefined( spawnpoint ) ) + { + if ( get_chugabug_spawn_point_from_nodes( self.origin, 100, 400, 64, 1 ) ) + { + spawnpoint = level.chugabud_spawn_struct; + } + } + if ( !isDefined( spawnpoint ) ) + { + if ( get_chugabug_spawn_point_from_nodes( self.origin, 50, 400, 256, 0 ) ) + { + spawnpoint = level.chugabud_spawn_struct; + } + } + 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" ); + if ( isdefined( structs ) ) + { + foreach ( struct in structs ) + { + if ( isdefined( struct.script_string ) ) + { + tokens = strtok( struct.script_string, " " ); + i = 0; + while ( i < tokens.size ) + { + if ( tokens[ i ] == match_string ) + { + spawnpoints[ spawnpoints.size ] = struct; + } + i++; + } + } + } + } + if ( !isDefined( spawnpoints ) || spawnpoints.size == 0 ) + { + spawnpoints = getstructarray( "initial_spawn_points", "targetname" ); + } + /* +/# + assert( isDefined( spawnpoints ), "Could not find initial spawn points!" ); +#/ + */ + spawnpoint = maps/mp/zombies/_zm::getfreespawnpoint( spawnpoints, self ); + } + return spawnpoint; +} + +get_chugabug_spawn_point_from_nodes( v_origin, min_radius, max_radius, max_height, ignore_targetted_nodes ) //checked partially changed to match cerberus output changed at own discretion +{ + if ( !isDefined( level.chugabud_spawn_struct ) ) + { + level.chugabud_spawn_struct = spawnstruct(); + } + found_node = undefined; + a_nodes = getnodesinradiussorted( v_origin, max_radius, min_radius, max_height, "pathnodes" ); + if ( 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; + } + } + 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; + } + } + } + } + i--; + } + } + if ( isDefined( found_node ) ) + { + level.chugabud_spawn_struct.origin = found_node.origin; + v_dir = vectornormalize( v_origin - level.chugabud_spawn_struct.origin ); + level.chugabud_spawn_struct.angles = vectorToAngles( v_dir ); + return 1; + } + return 0; +} + +force_corpse_respawn_position( forced_corpse_position ) //checked matches cerberus output +{ + level.chugabud_force_corpse_position = forced_corpse_position; +} + +force_player_respawn_position( forced_player_position ) //checked matches cerberus output +{ + level.chugabud_force_player_position = forced_player_position; +} + +save_weapons_for_chugabud( player ) //checked changed to match cerberus output +{ + self.chugabud_melee_weapons = []; + for ( i = 0; i < level._melee_weapons.size; i++ ) + { + self save_weapon_for_chugabud( player, level._melee_weapons[ i ].weapon_name ); + } +} + +save_weapon_for_chugabud( player, weapon_name ) //checked matches cerberus output +{ + if ( player hasweapon( weapon_name ) ) + { + self.chugabud_melee_weapons[ weapon_name ] = 1; + } +} + +restore_weapons_for_chugabud( player ) //checked changed to match cerberus output +{ + for ( i = 0; i < level._melee_weapons.size; i++ ) + { + self restore_weapon_for_chugabud( player, level._melee_weapons[ i ].weapon_name ); + } + self.chugabud_melee_weapons = undefined; +} + +restore_weapon_for_chugabud( player, weapon_name ) //checked changed to match cerberus output +{ + if ( !isDefined( weapon_name ) || !isDefined( self.chugabud_melee_weapons ) || !isDefined( self.chugabud_melee_weapons[ weapon_name ] ) ) + { + return; + } + if ( is_true( self.chugabud_melee_weapons[ weapon_name ] ) ) + { + player giveweapon( weapon_name ); + player set_player_melee_weapon( weapon_name ); + self.chugabud_melee_weapons[ weapon_name ] = 0; + } +} + +chugabud_save_perks( ent ) //checked changed to match cerberus output +{ + perk_array = ent get_perk_array( 1 ); + foreach ( perk in perk_array ) + { + ent unsetperk( perk ); + } + return perk_array; +} + +playchugabudtimeraudio() //checked matches cerberus output +{ + self endon( "chugabud_grabbed" ); + self endon( "chugabud_timedout" ); + player = self.player; + self thread playchugabudtimerout( player ); + while ( 1 ) + { + player playsoundtoplayer( "zmb_chugabud_timer_count", player ); + wait 1; + } +} + +playchugabudtimerout( player ) //checked matches cerberus output +{ + self endon( "chugabud_grabbed" ); + self waittill( "chugabud_timedout" ); + player playsoundtoplayer( "zmb_chugabud_timer_out", player ); +} + +chugabud_hostmigration() //checked changed to match cerberus output +{ + level endon( "end_game" ); + level notify( "chugabud_hostmigration" ); + level endon( "chugabud_hostmigration" ); + while ( 1 ) + { + level waittill( "host_migration_end" ); + chugabuds = getentarray( "player_chugabud_model", "script_noteworthy" ); + foreach ( model in chugabuds ) + { + playfxontag( level._effect[ "powerup_on" ], model, "tag_origin" ); + } + } +} + +player_revived_cleanup_chugabud_corpse() //checked matches cerberus output +{ +} + +player_has_chugabud_corpse() //checked matches cerberus output +{ + if ( isDefined( self.e_chugabud_corpse ) ) + { + return 1; + } + return 0; +} + +is_weapon_available_in_chugabud_corpse( weapon, player_to_check ) //checked partially changed to match cerberus output +{ + count = 0; + upgradedweapon = weapon; + if ( isDefined( level.zombie_weapons[ weapon ] ) && isDefined( level.zombie_weapons[ weapon ].upgrade_name ) ) + { + upgradedweapon = level.zombie_weapons[ weapon ].upgrade_name; + } + players = getplayers(); + if ( isDefined( players ) ) + { + player_index = 0; + while ( player_index < players.size ) + { + player = players[ player_index ]; + if ( isDefined( player_to_check ) && player != player_to_check ) + { + player_index++; + continue; + } + if ( player player_has_chugabud_corpse() ) + { + if ( isDefined( player.loadout ) && isDefined( player.loadout.weapons ) ) + { + for ( i = 0; i < player.loadout.weapons.size; i++ ) + { + chugabud_weapon = player.loadout.weapons[ i ]; + if ( isDefined( chugabud_weapon ) && chugabud_weapon[ "name" ] == weapon || chugabud_weapon[ "name" ] == upgradedweapon ) + { + count++; + } + } + } + } + player_index++; + } + } + return count; +} + +chugabud_corpse_cleanup_on_spectator( player ) //checked changed to match cerberus output +{ + self endon( "death" ); + player endon( "disconnect" ); + while ( 1 ) + { + if ( player.sessionstate == "spectator" ) + { + break; + } + wait 0.01; + } + player chugabud_corpse_cleanup( self, 0 ); +} + +chugabud_corpse_revive_icon( player ) //checked changed to match cerberus output +{ + self endon( "death" ); + height_offset = 30; + index = player.clientid; + hud_elem = newhudelem(); + self.revive_hud_elem = hud_elem; + hud_elem.x = self.origin[ 0 ]; + hud_elem.y = self.origin[ 1 ]; + hud_elem.z = self.origin[ 2 ] + height_offset; + hud_elem.alpha = 1; + hud_elem.archived = 1; + hud_elem setshader( "waypoint_revive", 5, 5 ); + hud_elem setwaypoint( 1 ); + hud_elem.hidewheninmenu = 1; + hud_elem.immunetodemogamehudsettings = 1; + while ( 1 ) + { + if ( !isDefined( self.revive_hud_elem ) ) + { + break; + } + hud_elem.x = self.origin[ 0 ]; + hud_elem.y = self.origin[ 1 ]; + hud_elem.z = self.origin[ 2 ] + height_offset; + wait 0.01; + } +} + +activate_chugabud_effects_and_audio() //checked matches cerberus output +{ + if ( isDefined( level.whos_who_client_setup ) ) + { + if ( !isDefined( self.whos_who_effects_active ) ) + { + if ( isDefined( level.chugabud_shellshock ) ) + { + self shellshock( "whoswho", 60 ); + } + if ( isDefined( level.vsmgr_prio_visionset_zm_whos_who ) ) + { + maps/mp/_visionset_mgr::vsmgr_activate( "visionset", "zm_whos_who", self ); + } + self setclientfieldtoplayer( "clientfield_whos_who_audio", 1 ); + self setclientfieldtoplayer( "clientfield_whos_who_filter", 1 ); + self.whos_who_effects_active = 1; + self thread deactivate_chugabud_effects_and_audio(); + } + } +} + +deactivate_chugabud_effects_and_audio() //checked matches cerberus output +{ + self waittill_any( "death", "chugabud_effects_cleanup" ); + if ( isDefined( level.whos_who_client_setup ) ) + { + if ( isDefined( self.whos_who_effects_active ) && self.whos_who_effects_active == 1 ) + { + if ( isDefined( level.chugabud_shellshock ) ) + { + self stopshellshock(); + } + if ( isDefined( level.vsmgr_prio_visionset_zm_whos_who ) ) + { + maps/mp/_visionset_mgr::vsmgr_deactivate( "visionset", "zm_whos_who", self ); + } + self setclientfieldtoplayer( "clientfield_whos_who_audio", 0 ); + self setclientfieldtoplayer( "clientfield_whos_who_filter", 0 ); + } + self.whos_who_effects_active = undefined; + } +} + + + + + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_equipment.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_equipment.gsc new file mode 100644 index 0000000..9f1549c --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_equipment.gsc @@ -0,0 +1,1905 @@ +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_buildables; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() //checked matches cerberus output +{ + init_equipment_upgrade(); + onplayerconnect_callback( ::equipment_placement_watcher ); + level._equipment_disappear_fx = loadfx( "maps/zombie/fx_zmb_tranzit_electrap_explo" ); + if ( !is_true( level.disable_fx_zmb_tranzit_shield_explo ) ) + { + level._riotshield_dissapear_fx = loadfx( "maps/zombie/fx_zmb_tranzit_shield_explo" ); + } + level.placeable_equipment_destroy_fn = []; + registerclientfield( "scriptmover", "equipment_activated", 12000, 4, "int" ); + + if ( !is_true( level._no_equipment_activated_clientfield ) ) + { + registerclientfield( "scriptmover", "equipment_activated", 12000, 4, "int" ); + } +} + +signal_equipment_activated( val ) //checked changed to match cerberus output +{ + if ( !isDefined( val ) ) + { + val = 1; + } + if ( is_true( level._no_equipment_activated_clientfield ) ) + { + return; + } + self endon( "death" ); + self setclientfield( "equipment_activated", val ); + for ( i = 0; i < 2; i++ ) + { + wait_network_frame(); + } + self setclientfield( "equipment_activated", 0 ); +} + +register_equipment( equipment_name, hint, howto_hint, hint_icon, equipmentvo, watcher_thread, transfer_fn, drop_fn, pickup_fn, place_fn ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_include_equipment ) || !is_true( level.zombie_include_equipment[ equipment_name ] ) ) + { + return; + } + precachestring( hint ); + if ( isDefined( hint_icon ) ) + { + precacheshader( hint_icon ); + } + struct = spawnstruct(); + if ( !isDefined( level.zombie_equipment ) ) + { + level.zombie_equipment = []; + } + struct.equipment_name = equipment_name; + struct.hint = hint; + struct.howto_hint = howto_hint; + struct.hint_icon = hint_icon; + struct.vox = equipmentvo; + struct.triggers = []; + struct.models = []; + struct.watcher_thread = watcher_thread; + struct.transfer_fn = transfer_fn; + struct.drop_fn = drop_fn; + struct.pickup_fn = pickup_fn; + struct.place_fn = place_fn; + level.zombie_equipment[ equipment_name ] = struct; +} + +is_equipment_included( equipment_name ) //checked changed at own discretion +{ + if ( !isDefined( level.zombie_include_equipment ) ) + { + return 0; + } + if ( !isDefined( level.zombie_include_equipment[ equipment_name ] ) ) + { + return 0; + } + if ( level.zombie_include_equipment[ equipment_name ] == 0 ) + { + return 0; + } + return 1; +} + +include_zombie_equipment( equipment_name ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_include_equipment ) ) + { + level.zombie_include_equipment = []; + } + level.zombie_include_equipment[ equipment_name ] = 1; + precacheitem( equipment_name ); +} + +limit_zombie_equipment( equipment_name, limited ) //checked matches cerberus output +{ + if ( !isDefined( level._limited_equipment ) ) + { + level._limited_equipment = []; + } + if ( limited ) + { + level._limited_equipment[ level._limited_equipment.size ] = equipment_name; + } + else + { + arrayremovevalue( level._limited_equipment, equipment_name, 0 ); + } +} + +init_equipment_upgrade() //checked changed to match cerberus output +{ + equipment_spawns = []; + equipment_spawns = getentarray( "zombie_equipment_upgrade", "targetname" ); + for ( i = 0; i < equipment_spawns.size; i++ ) + { + hint_string = get_equipment_hint( equipment_spawns[ i ].zombie_equipment_upgrade ); + equipment_spawns[ i ] sethintstring( hint_string ); + equipment_spawns[ i ] setcursorhint( "HINT_NOICON" ); + equipment_spawns[ i ] usetriggerrequirelookat(); + equipment_spawns[ i ] add_to_equipment_trigger_list( equipment_spawns[ i ].zombie_equipment_upgrade ); + equipment_spawns[ i ] thread equipment_spawn_think(); + } +} + +get_equipment_hint( equipment_name ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( level.zombie_equipment[ equipment_name ] ), equipment_name + " was not included or is not registered with the equipment system." ); +#/ +*/ + return level.zombie_equipment[ equipment_name ].hint; +} + +get_equipment_howto_hint( equipment_name ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( level.zombie_equipment[ equipment_name ] ), equipment_name + " was not included or is not registered with the equipment system." ); +#/ +*/ + return level.zombie_equipment[ equipment_name ].howto_hint; +} + +get_equipment_icon( equipment_name ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( level.zombie_equipment[ equipment_name ] ), equipment_name + " was not included or is not registered with the equipment system." ); +#/ +*/ + return level.zombie_equipment[ equipment_name ].hint_icon; +} + +add_to_equipment_trigger_list( equipment_name ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( level.zombie_equipment[ equipment_name ] ), equipment_name + " was not included or is not registered with the equipment system." ); +#/ +*/ + level.zombie_equipment[ equipment_name ].triggers[ level.zombie_equipment[ equipment_name ].triggers.size ] = self; + level.zombie_equipment[ equipment_name ].models[ level.zombie_equipment[ equipment_name ].models.size ] = getent( self.target, "targetname" ); +} + +equipment_spawn_think() //checked changed to match cerberus output +{ + for ( ;; ) + { + self waittill( "trigger", player ); + if ( player in_revive_trigger() || player.is_drinking > 0 ) + { + wait 0.1; + continue; + } + if ( is_limited_equipment( self.zombie_equipment_upgrade ) ) + { + player setup_limited_equipment( self.zombie_equipment_upgrade ); + if ( isDefined( level.hacker_tool_positions ) ) + { + new_pos = random( level.hacker_tool_positions ); + self.origin = new_pos.trigger_org; + model = getent( self.target, "targetname" ); + model.origin = new_pos.model_org; + model.angles = new_pos.model_ang; + } + } + player equipment_give( self.zombie_equipment_upgrade ); + } +} + +set_equipment_invisibility_to_player( equipment, invisible ) //checked changed to match cerberus output +{ + triggers = level.zombie_equipment[ equipment ].triggers; + for ( i = 0; i < triggers.size; i++ ) + { + if ( isDefined( triggers[ i ] ) ) + { + triggers[ i ] setinvisibletoplayer( self, invisible ); + } + } + models = level.zombie_equipment[ equipment ].models; + for ( i = 0; i < models.size; i++ ) + { + if ( isDefined( models[ i ] ) ) + { + models[ i ] setinvisibletoplayer( self, invisible ); + } + } +} + +equipment_take( equipment ) //checked matches cerberus output +{ + if ( !isDefined( equipment ) ) + { + equipment = self get_player_equipment(); + } + if ( !isDefined( equipment ) ) + { + return; + } + if ( !self has_player_equipment( equipment ) ) + { + return; + } + current = 0; + current_weapon = 0; + if ( isDefined( self get_player_equipment() ) && equipment == self get_player_equipment() ) + { + current = 1; + } + if ( equipment == self getcurrentweapon() ) + { + current_weapon = 1; + } + /* +/# + println( "ZM EQUIPMENT: " + self.name + " lost " + equipment + "\n" ); +#/ + */ + if ( is_true( self.current_equipment_active[ equipment ] ) ) + { + self.current_equipment_active[ equipment ] = 0; + self notify( equipment + "_deactivate" ); + } + self notify( equipment + "_taken" ); + self takeweapon( equipment ); + if ( !is_limited_equipment( equipment ) || is_limited_equipment( equipment ) && !limited_equipment_in_use( equipment ) ) + { + self set_equipment_invisibility_to_player( equipment, 0 ); + } + if ( current ) + { + self set_player_equipment( undefined ); + self setactionslot( 1, "" ); + } + else + { + arrayremovevalue( self.deployed_equipment, equipment ); + } + if ( current_weapon ) + { + primaryweapons = self getweaponslistprimaries(); + if ( isDefined( primaryweapons ) && primaryweapons.size > 0 ) + { + self switchtoweapon( primaryweapons[ 0 ] ); + } + } +} + +equipment_give( equipment ) //checked matches cerberus output +{ + if ( !isDefined( equipment ) ) + { + return; + } + if ( !isDefined( level.zombie_equipment[ equipment ] ) ) + { + return; + } + if ( self has_player_equipment( equipment ) ) + { + return; + } + /* +/# + println( "ZM EQUIPMENT: " + self.name + " got " + equipment + "\n" ); +#/ + */ + curr_weapon = self getcurrentweapon(); + curr_weapon_was_curr_equipment = self is_player_equipment( curr_weapon ); + self equipment_take(); + self set_player_equipment( equipment ); + self giveweapon( equipment ); + self setweaponammoclip( equipment, 1 ); + self thread show_equipment_hint( equipment ); + self notify( equipment + "_given" ); + self set_equipment_invisibility_to_player( equipment, 1 ); + self setactionslot( 1, "weapon", equipment ); + if ( isDefined( level.zombie_equipment[ equipment ].watcher_thread ) ) + { + self thread [[ level.zombie_equipment[ equipment ].watcher_thread ]](); + } + self thread equipment_slot_watcher( equipment ); + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", level.zombie_equipment[ equipment ].vox ); +} + +equipment_slot_watcher( equipment ) //checked changed to match cerberus output +{ + self notify( "kill_equipment_slot_watcher" ); + self endon( "kill_equipment_slot_watcher" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "weapon_change", curr_weapon, prev_weapon ); + self.prev_weapon_before_equipment_change = undefined; + if ( isDefined( prev_weapon ) && prev_weapon != "none" ) + { + prev_weapon_type = weaponinventorytype( prev_weapon ); + if ( prev_weapon_type == "primary" || prev_weapon_type == "altmode" ) + { + self.prev_weapon_before_equipment_change = prev_weapon; + } + } + if ( isDefined( level.zombie_equipment[ equipment ].watcher_thread ) ) + { + if ( curr_weapon == equipment ) + { + if ( self.current_equipment_active[ equipment ] == 1 ) + { + self notify( equipment + "_deactivate" ); + self.current_equipment_active[ equipment ] = 0; + } + else + { + if ( self.current_equipment_active[ equipment ] == 0 ) + { + self notify( equipment + "_activate" ); + self.current_equipment_active[ equipment ] = 1; + } + } + self waittill( "equipment_select_response_done" ); + } + } + else if ( curr_weapon == equipment && !self.current_equipment_active[ equipment ] ) + { + self notify( equipment + "_activate" ); + self.current_equipment_active[ equipment ] = 1; + } + else if ( curr_weapon != equipment && self.current_equipment_active[ equipment ] ) + { + self notify( equipment + "_deactivate" ); + self.current_equipment_active[ equipment ] = 0; + } + } +} + +is_limited_equipment( equipment ) //checked changed to match cerberus output +{ + if ( isDefined( level._limited_equipment ) ) + { + for ( i = 0; i < level._limited_equipment.size; i++ ) + { + if ( level._limited_equipment[ i ] == equipment ) + { + return 1; + } + } + } + return 0; +} + +limited_equipment_in_use( equipment ) //checked changed to match cerberus output +{ + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + current_equipment = players[ i ] get_player_equipment(); + if ( isDefined( current_equipment ) && current_equipment == equipment ) + { + return 1; + } + } + if ( isDefined( level.dropped_equipment ) && isDefined( level.dropped_equipment[ equipment ] ) ) + { + return 1; + } + return 0; +} + +setup_limited_equipment( equipment ) //checked changed to match cerberus output +{ + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + players[ i ] set_equipment_invisibility_to_player( equipment, 1 ); + } + self thread release_limited_equipment_on_disconnect( equipment ); + self thread release_limited_equipment_on_equipment_taken( equipment ); +} + +release_limited_equipment_on_equipment_taken( equipment ) //checked changed to match cerberus output +{ + self endon( "disconnect" ); + self waittill_either( equipment + "_taken", "spawned_spectator" ); + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + players[ i ] set_equipment_invisibility_to_player( equipment, 0 ); + } +} + +release_limited_equipment_on_disconnect( equipment ) //checked changed to match cerberus output +{ + self endon( equipment + "_taken" ); + self waittill( "disconnect" ); + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + if ( isalive( players[ i ] ) ) + { + players[ i ] set_equipment_invisibility_to_player( equipment, 0 ); + } + } +} + +is_equipment_active( equipment ) //changed at own discretion +{ + if ( !isDefined( self.current_equipment_active ) || !isDefined( self.current_equipment_active[ equipment ] ) ) + { + return 0; + } + if ( self.current_equipment_active[ equipment ] ) + { + return 1; + } + return 0; +} + +init_equipment_hint_hudelem( x, y, alignx, aligny, fontscale, alpha ) //checked matches cerberus output +{ + self.x = x; + self.y = y; + self.alignx = alignx; + self.aligny = aligny; + self.fontscale = fontscale; + self.alpha = alpha; + self.sort = 20; +} + +setup_equipment_client_hintelem() //checked matches cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( !isDefined( self.hintelem ) ) + { + self.hintelem = newclienthudelem( self ); + } + if ( level.splitscreen ) + { + self.hintelem init_equipment_hint_hudelem( 160, 90, "center", "middle", 1.6, 1 ); + } + else + { + self.hintelem init_equipment_hint_hudelem( 320, 220, "center", "bottom", 1.6, 1 ); + } +} + +show_equipment_hint( equipment ) //checked matches cerberus output +{ + self notify( "kill_previous_show_equipment_hint_thread" ); + self endon( "kill_previous_show_equipment_hint_thread" ); + self endon( "death" ); + self endon( "disconnect" ); + if ( is_true( self.do_not_display_equipment_pickup_hint ) ) + { + return; + } + wait 0.5; + text = get_equipment_howto_hint( equipment ); + self show_equipment_hint_text( text ); +} + +show_equipment_hint_text( text ) //checked matches cerberus output +{ + self notify( "hide_equipment_hint_text" ); + wait 0.05; + self setup_equipment_client_hintelem(); + self.hintelem settext( text ); + self.hintelem.alpha = 1; + self.hintelem.font = "small"; + self.hintelem.fontscale = 1.25; + self.hintelem.hidewheninmenu = 1; + time = self waittill_notify_or_timeout( "hide_equipment_hint_text", 3.2 ); + if ( isDefined( time ) ) + { + self.hintelem fadeovertime( 0.25 ); + self.hintelem.alpha = 0; + self waittill_notify_or_timeout( "hide_equipment_hint_text", 0.25 ); + } + self.hintelem settext( "" ); + self.hintelem destroy(); +} + +equipment_onspawnretrievableweaponobject( watcher, player ) //checked partially changed to match cerberus output changed at own discretion +{ + iswallmount = 0; + self.plant_parent = self; + if ( isDefined( level.placeable_equipment_type[ self.name ] ) && level.placeable_equipment_type[ self.name ] == "wallmount" ) + { + iswallmount = 1; + } + if ( !isDefined( player.turret_placement ) || !player.turret_placement[ "result" ] ) + { + if ( iswallmount /*|| !getDvarInt( #"B3416C1D" )*/ ) + { + self waittill( "stationary" ); + waittillframeend; + if ( iswallmount ) + { + if ( is_true( player.planted_wallmount_on_a_zombie ) ) + { + equip_name = self.name; + thread equipment_disappear_fx( self.origin, undefined, self.angles ); + self delete(); + if ( player hasweapon( equip_name ) ) + { + player setweaponammoclip( equip_name, 1 ); + } + player.planted_wallmount_on_a_zombie = undefined; + return; + } + } + } + else + { + self.plant_parent = player; + self.origin = player.origin; + self.angles = player.angles; + wait_network_frame(); + } + } + equipment = watcher.name + "_zm"; + /* +/# + if ( !isDefined( player.current_equipment ) || player.current_equipment != equipment ) + { + assert( player has_deployed_equipment( equipment ) ); + assert( !isDefined( player.current_equipment ) ); +#/ + } + */ + if ( isDefined( player.current_equipment ) && player.current_equipment == equipment ) + { + player equipment_to_deployed( equipment ); + } + if ( isDefined( level.zombie_equipment[ equipment ].place_fn ) ) + { + if ( isDefined( player.turret_placement ) && player.turret_placement[ "result" ] ) + { + plant_origin = player.turret_placement[ "origin" ]; + plant_angles = player.turret_placement[ "angles" ]; + } + else if ( isDefined( level.placeable_equipment_type[ self.name ] ) && level.placeable_equipment_type[ self.name ] == "wallmount" ) + { + plant_origin = self.origin; + plant_angles = self.angles; + } + else + { + plant_origin = self.origin; + plant_angles = self.angles; + } + if ( isDefined( level.check_force_deploy_origin ) ) + { + if ( player [[ level.check_force_deploy_origin ]]( self, plant_origin, plant_angles ) ) + { + plant_origin = player.origin; + plant_angles = player.angles; + self.plant_parent = player; + } + } + else if ( isDefined( level.check_force_deploy_z ) ) + { + if ( player [[ level.check_force_deploy_z ]]( self, plant_origin, plant_angles ) ) + { + plant_origin = ( plant_origin[ 0 ], plant_origin[ 1 ], player.origin[ 2 ] + 10 ); + } + } + if ( is_true( iswallmount ) ) + { + self ghost(); + } + replacement = player [[ level.zombie_equipment[ equipment ].place_fn ]]( plant_origin, plant_angles ); + if ( isDefined( replacement ) ) + { + replacement.owner = player; + replacement.original_owner = player; + replacement.name = self.name; + player notify( "equipment_placed" ); + if ( isDefined( level.equipment_planted ) ) + { + player [[ level.equipment_planted ]]( replacement, equipment, self.plant_parent ); + } + player maps/mp/zombies/_zm_buildables::track_buildables_planted( self ); + } + if ( isDefined( self ) ) + { + self delete(); + } + } +} + +equipment_retrieve( player ) //checked changed to match cerberus output +{ + if ( isDefined( self ) ) + { + self stoploopsound(); + original_owner = self.original_owner; + weaponname = self.name; + if ( !isDefined( original_owner ) ) + { + player equipment_give( weaponname ); + self.owner = player; + } + else if ( player != original_owner ) + { + equipment_transfer( weaponname, original_owner, player ); + self.owner = player; + } + player equipment_from_deployed( weaponname ); + if ( is_true( self.requires_pickup ) ) + { + if ( isDefined( level.zombie_equipment[ weaponname ].pickup_fn ) ) + { + self.owner = player; + if ( isDefined( self.damage ) ) + { + player player_set_equipment_damage( weaponname, self.damage ); + } + player [[ level.zombie_equipment[ weaponname ].pickup_fn ]]( self ); + } + } + self.playdialog = 0; + weaponname = self.name; + self delete(); + if ( !player hasweapon( weaponname ) ) + { + player giveweapon( weaponname ); + clip_ammo = player getweaponammoclip( weaponname ); + clip_max_ammo = weaponclipsize( weaponname ); + if ( clip_ammo < clip_max_ammo ) + { + clip_ammo++; + } + player setweaponammoclip( weaponname, clip_ammo ); + } + player maps/mp/zombies/_zm_buildables::track_planted_buildables_pickedup( weaponname ); + } +} + +equipment_drop_to_planted( equipment, player ) //checked matches cerberus output +{ +/* +/# + if ( !isDefined( player.current_equipment ) || player.current_equipment != equipment ) + { + assert( player has_deployed_equipment( equipment ) ); + assert( !isDefined( player.current_equipment ) ); +#/ + } +*/ + if ( isDefined( player.current_equipment ) && player.current_equipment == equipment ) + { + player equipment_to_deployed( equipment ); + } + if ( isDefined( level.zombie_equipment[ equipment ].place_fn ) ) + { + replacement = player [[ level.zombie_equipment[ equipment ].place_fn ]]( player.origin, player.angles ); + if ( isDefined( replacement ) ) + { + replacement.owner = player; + replacement.original_owner = player; + replacement.name = equipment; + if ( isDefined( level.equipment_planted ) ) + { + player [[ level.equipment_planted ]]( replacement, equipment, player ); + } + player notify( "equipment_placed" ); + player maps/mp/zombies/_zm_buildables::track_buildables_planted( replacement ); + } + } +} + +equipment_transfer( weaponname, fromplayer, toplayer ) //checked matches cerberus output +{ + if ( is_limited_equipment( weaponname ) ) + { +/* +/# + println( "ZM EQUIPMENT: " + weaponname + " transferred from " + fromplayer.name + " to " + toplayer.name + "\n" ); +#/ +*/ + toplayer equipment_orphaned( weaponname ); + wait 0.05; +/* +/# + assert( !toplayer has_player_equipment( weaponname ) ); +#/ +/# + assert( fromplayer has_player_equipment( weaponname ) ); +#/ +*/ + toplayer equipment_give( weaponname ); + toplayer equipment_to_deployed( weaponname ); + if ( isDefined( level.zombie_equipment[ weaponname ].transfer_fn ) ) + { + [[ level.zombie_equipment[ weaponname ].transfer_fn ]]( fromplayer, toplayer ); + } + fromplayer equipment_release( weaponname ); +/* +/# + assert( toplayer has_player_equipment( weaponname ) ); +#/ +/# + assert( !fromplayer has_player_equipment( weaponname ) ); +#/ +*/ + equipment_damage = 0; + toplayer player_set_equipment_damage( weaponname, fromplayer player_get_equipment_damage( weaponname ) ); + fromplayer player_set_equipment_damage( equipment_damage ); + } + else + { +/* +/# + println( "ZM EQUIPMENT: " + weaponname + " swapped from " + fromplayer.name + " to " + toplayer.name + "\n" ); +#/ +*/ + toplayer equipment_give( weaponname ); + if ( isDefined( toplayer.current_equipment ) && toplayer.current_equipment == weaponname ) + { + toplayer equipment_to_deployed( weaponname ); + } + if ( isDefined( level.zombie_equipment[ weaponname ].transfer_fn ) ) + { + [[ level.zombie_equipment[ weaponname ].transfer_fn ]]( fromplayer, toplayer ); + } + equipment_damage = toplayer player_get_equipment_damage( weaponname ); + toplayer player_set_equipment_damage( weaponname, fromplayer player_get_equipment_damage( weaponname ) ); + fromplayer player_set_equipment_damage( weaponname, equipment_damage ); + } +} + +equipment_release( equipment ) //checked matches cerberus output +{ +/* +/# + println( "ZM EQUIPMENT: " + self.name + " release " + equipment + "\n" ); +#/ +*/ + self equipment_take( equipment ); +} + +equipment_drop( equipment ) //checked matches cerberus output +{ + if ( isDefined( level.zombie_equipment[ equipment ].place_fn ) ) + { + equipment_drop_to_planted( equipment, self ); +/* +/# + println( "ZM EQUIPMENT: " + self.name + " drop to planted " + equipment + "\n" ); +#/ +*/ + } + else if ( isDefined( level.zombie_equipment[ equipment ].drop_fn ) ) + { + if ( isDefined( self.current_equipment ) && self.current_equipment == equipment ) + { + self equipment_to_deployed( equipment ); + } + item = self [[ level.zombie_equipment[ equipment ].drop_fn ]](); + if ( isDefined( item ) ) + { + if ( isDefined( level.equipment_planted ) ) + { + self [[ level.equipment_planted ]]( item, equipment, self ); + } + item.owner = undefined; + item.damage = self player_get_equipment_damage( equipment ); + } +/* +/# + println( "ZM EQUIPMENT: " + self.name + " dropped " + equipment + "\n" ); +#/ +*/ + } + else + { + self equipment_take(); + } + self notify( "equipment_dropped" ); +} + +equipment_grab( equipment, item ) //checked matches cerberus output +{ +/* +/# + println( "ZM EQUIPMENT: " + self.name + " picked up " + equipment + "\n" ); +#/ +*/ + self equipment_give( equipment ); + if ( isDefined( level.zombie_equipment[ equipment ].pickup_fn ) ) + { + item.owner = self; + self player_set_equipment_damage( equipment, item.damage ); + self [[ level.zombie_equipment[ equipment ].pickup_fn ]]( item ); + } +} + +equipment_orphaned( equipment ) //checked matches cerberus output +{ +/* +/# + println( "ZM EQUIPMENT: " + self.name + " orphaned " + equipment + "\n" ); +#/ +*/ + self equipment_take( equipment ); +} + +equipment_to_deployed( equipment ) //checked matches cerberus output +{ +/* +/# + println( "ZM EQUIPMENT: " + self.name + " deployed " + equipment + "\n" ); +#/ +*/ + if ( !isDefined( self.deployed_equipment ) ) + { + self.deployed_equipment = []; + } +/* +/# + assert( self.current_equipment == equipment ); +#/ +*/ + self.deployed_equipment[ self.deployed_equipment.size ] = equipment; + self.current_equipment = undefined; + if ( !isDefined( level.riotshield_name ) || equipment != level.riotshield_name ) + { + self takeweapon( equipment ); + } + self setactionslot( 1, "" ); +} + +equipment_from_deployed( equipment ) //checked matches cerberus output +{ + if ( !isDefined( equipment ) ) + { + equipment = "none"; + } +/* +/# + println( "ZM EQUIPMENT: " + self.name + " retrieved " + equipment + "\n" ); +#/ +*/ + if ( isDefined( self.current_equipment ) && equipment != self.current_equipment ) + { + self equipment_drop( self.current_equipment ); + } +/* +/# + assert( self has_deployed_equipment( equipment ) ); +#/ +*/ + self.current_equipment = equipment; + if ( isDefined( level.riotshield_name ) && equipment != level.riotshield_name ) + { + self giveweapon( equipment ); + } + if ( self hasweapon( equipment ) ) + { + self setweaponammoclip( equipment, 1 ); + } + self setactionslot( 1, "weapon", equipment ); + arrayremovevalue( self.deployed_equipment, equipment ); + self notify( equipment + "_pickup" ); +} + +eqstub_get_unitrigger_origin() //checked matches cerberus output +{ + if ( isDefined( self.origin_parent ) ) + { + return self.origin_parent.origin; + } + tup = anglesToUp( self.angles ); + eq_unitrigger_offset = 12 * tup; + return self.origin + eq_unitrigger_offset; +} + +eqstub_on_spawn_trigger( trigger ) //checked matches cerberus output +{ + if ( isDefined( self.link_parent ) ) + { + trigger enablelinkto(); + trigger linkto( self.link_parent ); + trigger setmovingplatformenabled( 1 ); + } +} + +equipment_buy( equipment ) //checked changed at own discretion +{ +/* +/# + println( "ZM EQUIPMENT: " + self.name + " bought " + equipment + "\n" ); +#/ +*/ + if ( isDefined( self.current_equipment ) && equipment != self.current_equipment ) + { + self equipment_drop( self.current_equipment ); + } + if ( ( equipment == "riotshield_zm" || equipment == "alcatraz_shield_zm" ) && isDefined( self.player_shield_reset_health ) ) + { + self [[ self.player_shield_reset_health ]](); + } + else + { + self player_set_equipment_damage( equipment, 0 ); + } + self equipment_give( equipment ); +} + +generate_equipment_unitrigger( classname, origin, angles, flags, radius, script_height, hint, icon, think, moving ) //checked matches cerberus output +{ + if ( !isDefined( radius ) ) + { + radius = 64; + } + if ( !isDefined( script_height ) ) + { + script_height = 64; + } + script_width = script_height; + if ( !isDefined( script_width ) ) + { + script_width = 64; + } + script_length = script_height; + if ( !isDefined( script_length ) ) + { + script_length = 64; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.origin = origin; + if ( isDefined( angles ) ) + { + unitrigger_stub.angles = angles; + } + if ( isDefined( script_length ) ) + { + unitrigger_stub.script_length = script_length; + } + else + { + unitrigger_stub.script_length = 13.5; + } + if ( isDefined( script_width ) ) + { + unitrigger_stub.script_width = script_width; + } + else + { + unitrigger_stub.script_width = 27.5; + } + if ( isDefined( script_height ) ) + { + unitrigger_stub.script_height = script_height; + } + else + { + unitrigger_stub.script_height = 24; + } + unitrigger_stub.radius = radius; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + unitrigger_stub.hint_string = hint; + /* + if ( getDvarInt( #"1F0A2129" ) ) + { + unitrigger_stub.cursor_hint = "HINT_WEAPON"; + unitrigger_stub.cursor_hint_weapon = icon; + } + */ + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + unitrigger_stub.require_look_at = 0; + switch( classname ) + { + case "trigger_radius": + unitrigger_stub.script_unitrigger_type = "unitrigger_radius"; + break; + case "trigger_radius_use": + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + break; + case "trigger_box": + unitrigger_stub.script_unitrigger_type = "unitrigger_box"; + break; + case "trigger_box_use": + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + break; + } + unitrigger_stub.originfunc = ::eqstub_get_unitrigger_origin; + unitrigger_stub.onspawnfunc = ::eqstub_on_spawn_trigger; + if ( is_true( moving ) ) + { + maps/mp/zombies/_zm_unitrigger::register_unitrigger( unitrigger_stub, think ); + } + else + { + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, think ); + } + return unitrigger_stub; +} + +can_pick_up_equipment( equipment_name, equipment_trigger ) //checked matches cerberus output +{ + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || self in_revive_trigger() ) + { + return 0; + } + if ( self isthrowinggrenade() ) + { + return 0; + } + if ( isDefined( self.screecher_weapon ) ) + { + return 0; + } + if ( self is_jumping() ) + { + return 0; + } + if ( self is_player_equipment( equipment_name ) ) + { + return 0; + } + if ( is_true( self.pickup_equipment ) ) + { + return 0; + } + if ( is_true( level.equipment_team_pick_up ) && !self same_team_placed_equipment( equipment_trigger ) ) + { + return 0; + } + return 1; +} + +same_team_placed_equipment( equipment_trigger ) //checked changed at own discretion +{ + if ( isDefined( equipment_trigger ) && isDefined( equipment_trigger.stub ) && isDefined( equipment_trigger.stub.model ) && isDefined( equipment_trigger.stub.model.owner ) && equipment_trigger.stub.model.owner.pers[ "team" ] == self.pers[ "team" ] ) + { + return 1; + } + return 0; +} + +placed_equipment_think( model, equipname, origin, angles, tradius, toffset ) //checked changed to match cerberus output +{ + pickupmodel = spawn( "script_model", origin ); + if ( isDefined( angles ) ) + { + pickupmodel.angles = angles; + } + pickupmodel setmodel( model ); + if ( isDefined( level.equipment_safe_to_drop ) ) + { + if ( !( self [[ level.equipment_safe_to_drop ]]( pickupmodel ) ) ) + { + equipment_disappear_fx( pickupmodel.origin, undefined, pickupmodel.angles ); + pickupmodel delete(); + self equipment_take( equipname ); + return undefined; + } + } + watchername = getsubstr( equipname, 0, equipname.size - 3 ); + if ( isDefined( level.retrievehints[ watchername ] ) ) + { + hint = level.retrievehints[ watchername ].hint; + } + else + { + hint = &"MP_GENERIC_PICKUP"; + } + icon = get_equipment_icon( equipname ); + if ( !isDefined( tradius ) ) + { + tradius = 32; + } + torigin = origin; + if ( isDefined( toffset ) ) + { + tforward = anglesToForward( angles ); + torigin += toffset * tforward; + } + tup = anglesToUp( angles ); + eq_unitrigger_offset = 12 * tup; + pickupmodel.stub = generate_equipment_unitrigger( "trigger_radius_use", torigin + eq_unitrigger_offset, angles, 0, tradius, 64, hint, equipname, ::placed_equipment_unitrigger_think, pickupmodel.canmove ); + pickupmodel.stub.model = pickupmodel; + pickupmodel.stub.equipname = equipname; + pickupmodel.equipname = equipname; + pickupmodel thread item_attract_zombies(); + pickupmodel thread item_watch_explosions(); + if ( is_limited_equipment( equipname ) ) + { + if ( !isDefined( level.dropped_equipment ) ) + { + level.dropped_equipment = []; + } + if ( isDefined( level.dropped_equipment[ equipname ] ) && isDefined( level.dropped_equipment[ equipname ].model ) ) + { + level.dropped_equipment[ equipname ].model dropped_equipment_destroy( 1 ); + } + level.dropped_equipment[ equipname ] = pickupmodel.stub; + } + destructible_equipment_list_add( pickupmodel ); + return pickupmodel; +} + +watch_player_visibility( equipment ) //checked partially changed to match cerberus output continue in foreach bad check the github for more info +{ + self endon( "kill_trigger" ); + self setinvisibletoall(); + while ( isDefined( self ) ) + { + players = getplayers(); + i = 0; + while ( i < players.size ) + { + if ( !isDefined( player ) ) + { + i++; + continue; + } + invisible = !player can_pick_up_equipment( equipment, self ); + if ( isDefined( self ) ) + { + self setinvisibletoplayer( player, invisible ); + } + wait 0.05; + i++; + } + wait 1; + } +} + +placed_equipment_unitrigger_think() //checked matches cerberus output +{ + self endon( "kill_trigger" ); + self thread watch_player_visibility( self.stub.equipname ); + while ( 1 ) + { + self waittill( "trigger", player ); + while ( !player can_pick_up_equipment( self.stub.equipname, self ) ) + { + continue; + } + self thread pickup_placed_equipment( player ); + return; + } +} + +pickup_placed_equipment( player ) //checked changed to match cerberus output +{ +/* +/# + if ( isDefined( player.pickup_equipment )assert( !player.pickup_equipment ); +#/ +*/ + player.pickup_equipment = 1; + stub = self.stub; + if ( isDefined( player.current_equipment ) && stub.equipname != player.current_equipment ) + { + player equipment_drop( player.current_equipment ); + } + if ( is_limited_equipment( stub.equipname ) ) + { + if ( isDefined( level.dropped_equipment ) && isDefined( level.dropped_equipment[ stub.equipname ] ) && level.dropped_equipment[ stub.equipname ] == stub ) + { + level.dropped_equipment[stub.equipname] = undefined; + } + } + if ( isDefined( stub.model ) ) + { + stub.model equipment_retrieve( player ); + } + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( stub ); + wait 3; + player.pickup_equipment = 0; +} + +dropped_equipment_think( model, equipname, origin, angles, tradius, toffset ) //checked changed to match cerberus output +{ + pickupmodel = spawn( "script_model", origin ); + if ( isDefined( angles ) ) + { + pickupmodel.angles = angles; + } + pickupmodel setmodel( model ); + if ( isDefined( level.equipment_safe_to_drop ) ) + { + if ( !self [[ level.equipment_safe_to_drop ]]( pickupmodel ) ) + { + equipment_disappear_fx( pickupmodel.origin, undefined, pickupmodel.angles ); + pickupmodel delete(); + self equipment_take( equipname ); + return; + } + } + watchername = getsubstr( equipname, 0, equipname.size - 3 ); + if ( isDefined( level.retrievehints[ watchername ] ) ) + { + hint = level.retrievehints[ watchername ].hint; + } + else + { + hint = &"MP_GENERIC_PICKUP"; + } + icon = get_equipment_icon( equipname ); + if ( !isDefined( tradius ) ) + { + tradius = 32; + } + torigin = origin; + if ( isDefined( toffset ) ) + { + offset = 64; + tforward = anglesToForward( angles ); + torigin = torigin + toffset * tforward + vectorScale( ( 0, 0, 1 ), 8 ); + } + if ( isDefined( pickupmodel.canmove ) ) + { + pickupmodel.stub = generate_equipment_unitrigger( "trigger_radius_use", torigin, angles, 0, tradius, 64, hint, equipname, ::dropped_equipment_unitrigger_think, pickupmodel.canmove ); + } + pickupmodel.stub.model = pickupmodel; + pickupmodel.stub.equipname = equipname; + pickupmodel.equipname = equipname; + if ( isDefined( level.equipment_planted ) ) + { + self [[ level.equipment_planted ]]( pickupmodel, equipname, self ); + } + if ( !isDefined( level.dropped_equipment ) ) + { + level.dropped_equipment = []; + } + if ( isDefined( level.dropped_equipment[ equipname ] ) ) + { + level.dropped_equipment[ equipname ].model dropped_equipment_destroy( 1 ); + } + level.dropped_equipment[ equipname ] = pickupmodel.stub; + destructible_equipment_list_add( pickupmodel ); + pickupmodel thread item_attract_zombies(); + return pickupmodel; +} + +dropped_equipment_unitrigger_think() //checked matches cerberus output +{ + self endon( "kill_trigger" ); + self thread watch_player_visibility( self.stub.equipname ); + while ( 1 ) + { + self waittill( "trigger", player ); + while ( !player can_pick_up_equipment( self.stub.equipname, self ) ) + { + continue; + } + self thread pickup_dropped_equipment( player ); + return; + } +} + +pickup_dropped_equipment( player ) //checked matches cerberus output +{ + player.pickup_equipment = 1; + stub = self.stub; + if ( isDefined( player.current_equipment ) && stub.equipname != player.current_equipment ) + { + player equipment_drop( player.current_equipment ); + } + player equipment_grab( stub.equipname, stub.model ); + stub.model dropped_equipment_destroy(); + wait 3; + player.pickup_equipment = 0; +} + +dropped_equipment_destroy( gusto ) //checked changed to match cerberus output +{ + stub = self.stub; + if ( is_true( gusto ) ) + { + equipment_disappear_fx( self.origin, undefined, self.angles ); + } + if ( isDefined( level.dropped_equipment ) ) + { + } + if ( isDefined( stub.model ) ) + { + stub.model delete(); + } + if ( isDefined( self.original_owner ) && is_limited_equipment( stub.equipname ) || maps/mp/zombies/_zm_weapons::is_weapon_included( stub.equipname ) ) + { + self.original_owner equipment_take( stub.equipname ); + } + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( stub ); +} + +add_placeable_equipment( equipment, modelname, destroy_fn, type ) //checked matches cerberus output +{ + if ( !isDefined( level.placeable_equipment ) ) + { + level.placeable_equipment = []; + } + level.placeable_equipment[ equipment ] = modelname; + precachemodel( modelname ); + precacheitem( equipment + "_turret" ); + if ( !isDefined( level.placeable_equipment_destroy_fn ) ) + { + level.placeable_equipment_destroy_fn = []; + } + level.placeable_equipment_destroy_fn[ equipment ] = destroy_fn; + if ( !isDefined( level.placeable_equipment_type ) ) + { + level.placeable_equipment_type = []; + } + level.placeable_equipment_type[ equipment ] = type; +} + +is_placeable_equipment( equipment ) //checked matches cerberus output +{ + if ( isDefined( level.placeable_equipment ) && isDefined( level.placeable_equipment[ equipment ] ) ) + { + return 1; + } + return 0; +} + +equipment_placement_watcher() //checked matches cerberus output +{ + self endon( "death_or_disconnect" ); + for ( ;; ) + { + self waittill( "weapon_change", weapon ); + if ( self.sessionstate != "spectator" && is_placeable_equipment( weapon ) ) + { + self thread equipment_watch_placement( weapon ); + } + } +} + +equipment_watch_placement( equipment ) //checked changed to match cerberus output +{ + self.turret_placement = undefined; + carry_offset = vectorScale( ( 1, 0, 0 ), 22 ); + carry_angles = ( 0, 0, 0 ); + placeturret = spawnturret( "auto_turret", self.origin, equipment + "_turret" ); + placeturret.angles = self.angles; + placeturret setmodel( level.placeable_equipment[ equipment ] ); + placeturret setturretcarried( 1 ); + placeturret setturretowner( self ); + if ( isDefined( level.placeable_equipment_type[ equipment ] ) ) + { + placeturret setturrettype( level.placeable_equipment_type[ equipment ] ); + } + self carryturret( placeturret, carry_offset, carry_angles ); + if ( isDefined( level.use_swipe_protection ) ) + { + self thread watch_melee_swipes( equipment, placeturret ); + } + self notify( "create_equipment_turret", placeturret ); + ended = self waittill_any_return( "weapon_change", "grenade_fire", "death_or_disconnect" ); + if ( !is_true( level.use_legacy_equipment_placement ) ) + { + self.turret_placement = self canplayerplaceturret( placeturret ); + } + if ( ended == "weapon_change" ) + { + self.turret_placement = undefined; + if ( self hasweapon( equipment ) ) + { + self setweaponammoclip( equipment, 1 ); + } + } + self notify( "destroy_equipment_turret" ); + self stopcarryturret( placeturret ); + placeturret setturretcarried( 0 ); + placeturret delete(); +} + +watch_melee_swipes( equipment, turret ) //checked matches cerberus output +{ + self endon( "weapon_change" ); + self endon( "grenade_fire" ); + self endon( "death" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "melee_swipe", zombie ); + while ( distancesquared( zombie.origin, self.origin ) > ( zombie.meleeattackdist * zombie.meleeattackdist ) ) + { + continue; + } + tpos = turret.origin; + tangles = turret.angles; + self player_damage_equipment( equipment, 200, zombie.origin ); + if ( self.equipment_damage[ equipment ] >= 1500 ) + { + thread equipment_disappear_fx( tpos, undefined, tangles ); + primaryweapons = self getweaponslistprimaries(); + if ( isDefined( primaryweapons[ 0 ] ) ) + { + self switchtoweapon( primaryweapons[ 0 ] ); + } + if ( isalive( self ) ) + { + self playlocalsound( level.zmb_laugh_alias ); + } + self maps/mp/zombies/_zm_stats::increment_client_stat( "cheat_total", 0 ); + self equipment_release( equipment ); + return; + } + } +} + +player_get_equipment_damage( equipment ) //checked matches cerberus output +{ + if ( isDefined( self.equipment_damage ) && isDefined( self.equipment_damage[ equipment ] ) ) + { + return self.equipment_damage[ equipment ]; + } + return 0; +} + +player_set_equipment_damage( equipment, damage ) //checked matches cerberus output +{ + if ( !isDefined( self.equipment_damage ) ) + { + self.equipment_damage = []; + } + self.equipment_damage[ equipment ] = damage; +} + +player_damage_equipment( equipment, damage, origin ) //checked matches cerberus output +{ + if ( !isDefined( self.equipment_damage ) ) + { + self.equipment_damage = []; + } + if ( !isDefined( self.equipment_damage[ equipment ] ) ) + { + self.equipment_damage[ equipment ] = 0; + } + self.equipment_damage[ equipment ] += damage; + if ( self.equipment_damage[ equipment ] > 1500 ) + { + if ( isDefined( level.placeable_equipment_destroy_fn[ equipment ] ) ) + { + self [[ level.placeable_equipment_destroy_fn[ equipment ] ]](); + } + else + { + equipment_disappear_fx( origin ); + } + self equipment_release( equipment ); + } +} + +item_damage( damage ) //checked changed to match cerberus output +{ + if ( is_true( self.isriotshield ) ) + { + if ( isDefined( level.riotshield_damage_callback ) && isDefined( self.owner ) ) + { + self.owner [[ level.riotshield_damage_callback ]]( damage, 0 ); + } + else if ( isDefined( level.deployed_riotshield_damage_callback ) ) + { + self [[ level.deployed_riotshield_damage_callback ]]( damage ); + } + } + else if ( isDefined( self.owner ) ) + { + self.owner player_damage_equipment( self.equipname, damage, self.origin ); + return; + } + else if ( !isDefined( self.damage ) ) + { + self.damage = 0; + } + self.damage += damage; + if ( self.damage > 1500 ) + { + self thread dropped_equipment_destroy( 1 ); + } +} + +item_watch_damage() //checked matches cerberus output +{ + self endon( "death" ); + self setcandamage( 1 ); + self.health = 1500; + while ( 1 ) + { + self waittill( "damage", amount ); + self item_damage( amount ); + } +} + +item_watch_explosions() //checked matches cerberus output may need to check order of operations +{ + self endon( "death" ); + while ( 1 ) + { + level waittill( "grenade_exploded", position, radius, idamage, odamage ); + wait randomfloatrange( 0.05, 0.3 ); + distsqrd = distancesquared( self.origin, position ); + if ( distsqrd < radius * radius ) + { + dist = sqrt( distsqrd ); + dist /= radius; + damage = odamage + ( ( idamage - odamage ) * ( 1 - dist ) ); + self item_damage( damage * 5 ); + } + } +} + +get_item_health() //dev call did not check +{ +/* +/# + damage = 0; + if ( isDefined( self.isriotshield ) && self.isriotshield ) + { + damagemax = level.zombie_vars[ "riotshield_hit_points" ]; + if ( isDefined( self.owner ) ) + { + damage = self.owner.shielddamagetaken; + } + else + { + if ( isDefined( level.deployed_riotshield_damage_callback ) ) + { + damage = self.shielddamagetaken; + } + } + } + else + { + if ( isDefined( self.owner ) ) + { + damagemax = 1500; + damage = self.owner player_get_equipment_damage( self.equipname ); + } + else + { + damagemax = 1500; + if ( isDefined( self.damage ) ) + { + damage = self.damage; + } + } + } + return ( damagemax - damage ) / damagemax; +#/ +*/ +} + +debughealth() //dev call did not check +{ +/* +/# + self endon( "death" ); + self endon( "stop_attracting_zombies" ); + while ( 1 ) + { + if ( getDvarInt( #"EB512CB7" ) ) + { + health = self get_item_health(); + color = ( 1 - health, health, 0 ); + text = "" + ( health * 100 ) + ""; + print3d( self.origin, text, color, 1, 0,5, 1 ); + } + wait 0.05; +#/ + } +*/ +} + +item_choke() //checked matches cerberus output +{ + if ( !isDefined( level.item_choke_count ) ) + { + level.item_choke_count = 0; + } + level.item_choke_count++; + if ( level.item_choke_count >= 10 ) + { + wait 0.05; + level.item_choke_count = 0; + } +} + +is_equipment_ignored( equipname ) //checked matches cerberus output +{ + if ( isDefined( level.equipment_ignored_by_zombies ) && isDefined( equipname ) && isDefined( level.equipment_ignored_by_zombies[ equipname ] ) ) + { + return 1; + } + return 0; +} + +enemies_ignore_equipment( equipname ) //checked matches cerberus output +{ + if ( !isDefined( level.equipment_ignored_by_zombies ) ) + { + level.equipment_ignored_by_zombies = []; + } + level.equipment_ignored_by_zombies[ equipname ] = equipname; +} + +item_attract_zombies() //checked partially changed to match cerberus output did not change for loop to while loop more info on the github about continues +{ + self endon( "death" ); + self notify( "stop_attracting_zombies" ); + self endon( "stop_attracting_zombies" ); +/* +/# + self thread debughealth(); +#/ +*/ + if ( is_equipment_ignored( self.equipname ) ) + { + return; + } + while ( 1 ) + { + if ( isDefined( level.vert_equipment_attack_range ) ) + { + vdistmax = level.vert_equipment_attack_range; + } + else + { + vdistmax = 36; + } + if ( isDefined( level.max_equipment_attack_range ) ) + { + distmax = level.max_equipment_attack_range * level.max_equipment_attack_range; + } + else + { + distmax = 4096; + } + if ( isDefined( level.min_equipment_attack_range ) ) + { + distmin = level.min_equipment_attack_range * level.min_equipment_attack_range; + } + else + { + distmin = 2025; + } + ai = getaiarray( level.zombie_team ); + i = 0; + while ( i < ai.size ) + { + if ( !isDefined( ai[ i ] ) ) + { + i++; + continue; + } + if ( is_true( ai[ i ].ignore_equipment ) ) + { + i++; + continue; + } + if ( isDefined( level.ignore_equipment ) ) + { + if ( self [[ level.ignore_equipment ]]( ai[ i ] ) ) + { + i++; + continue; + } + } + if ( is_true( ai[ i ].is_inert ) ) + { + i++; + continue; + } + if ( is_true( ai[ i ].is_traversing ) ) + { + i++; + continue; + } + vdist = abs( ai[ i ].origin[ 2 ] - self.origin[ 2 ] ); + distsqrd = distance2dsquared( ai[ i ].origin, self.origin ); + if ( ( self.equipname == "riotshield_zm" || self.equipname == "alcatraz_shield_zm" ) && isDefined( self.equipname ) ) + { + vdistmax = 108; + } + should_attack = 0; + if ( isDefined( level.should_attack_equipment ) ) + { + should_attack = self [[ level.should_attack_equipment ]]( distsqrd ); + } + if ( distsqrd < distmax && distsqrd > distmin && vdist < vdistmax || should_attack ) + { + if ( !is_true( ai[ i ].isscreecher ) && !ai[ i ] is_quad() && !ai[ i ] is_leaper() ) + { + ai[ i ] thread attack_item( self ); + item_choke(); + } + } + item_choke(); + i++; + } + wait 0.1; + } +} + +attack_item( item ) //checked changed to match cerberus output +{ + self endon( "death" ); + item endon( "death" ); + self endon( "start_inert" ); + if ( is_true( self.doing_equipment_attack ) ) + { + return 0; + } + if ( is_true( self.not_interruptable ) ) + { + return 0; + } + self thread attack_item_stop( item ); + self thread attack_item_interrupt( item ); + if ( getDvar( "zombie_equipment_attack_freq" ) == "" ) + { + setdvar( "zombie_equipment_attack_freq", "15" ); + } + freq = getDvarInt( "zombie_equipment_attack_freq" ); + self.doing_equipment_attack = 1; + self maps/mp/zombies/_zm_spawner::zombie_history( "doing equipment attack 1 - " + getTime() ); + self.item = item; + if ( !isDefined( self ) || !isalive( self ) ) + { + return; + } + if ( isDefined( item.zombie_attack_callback ) ) + { + item [[ item.zombie_attack_callback ]]( self ); + } + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "attack", self.animname ); + if ( isDefined( level.attack_item ) ) + { + self [[ level.attack_item ]](); + } + melee_anim = "zm_window_melee"; + if ( !self.has_legs ) + { + melee_anim = "zm_walk_melee_crawl"; + if ( self.a.gib_ref == "no_legs" ) + { + melee_anim = "zm_stumpy_melee"; + } + else if ( self.zombie_move_speed == "run" || self.zombie_move_speed == "sprint" ) + { + melee_anim = "zm_run_melee_crawl"; + } + } + self orientmode( "face point", item.origin ); + self animscripted( self.origin, flat_angle( vectorToAngles( item.origin - self.origin ) ), melee_anim ); + self notify( "item_attack" ); + if ( isDefined( self.custom_item_dmg ) ) + { + item thread item_damage( self.custom_item_dmg ); + } + else + { + item thread item_damage( 100 ); + } + item playsound( "fly_riotshield_zm_impact_flesh" ); + wait ( randomint( 100 ) / 100 ); + self.doing_equipment_attack = 0; + self maps/mp/zombies/_zm_spawner::zombie_history( "doing equipment attack 0 from wait - " + getTime() ); + self orientmode( "face default" ); +} + +attack_item_interrupt( item ) //checked matches cerberus output +{ + if ( !is_true( self.has_legs ) ) + { + return; + } + self notify( "attack_item_interrupt" ); + self endon( "attack_item_interrupt" ); + self endon( "death" ); + while ( is_true( self.has_legs ) ) + { + self waittill( "damage" ); + } + self stopanimscripted(); + self.doing_equipment_attack = 0; + self maps/mp/zombies/_zm_spawner::zombie_history( "doing equipment attack 0 from death - " + getTime() ); + self.item = undefined; +} + +attack_item_stop( item ) //checked matches cerberus output +{ + self notify( "attack_item_stop" ); + self endon( "attack_item_stop" ); + self endon( "death" ); + item waittill( "death" ); + self stopanimscripted(); + self.doing_equipment_attack = 0; + self maps/mp/zombies/_zm_spawner::zombie_history( "doing equipment attack 0 from death - " + getTime() ); + self.item = undefined; + if ( isDefined( level.attack_item_stop ) ) + { + self [[ level.attack_item_stop ]](); + } +} + +window_notetracks( msg, equipment ) //checked matches cerberus output +{ + self endon( "death" ); + equipment endon( "death" ); + while ( self.doing_equipment_attack ) + { + self waittill( msg, notetrack ); + if ( notetrack == "end" ) + { + return; + } + if ( notetrack == "fire" ) + { + equipment item_damage( 100 ); + } + } +} + +destructible_equipment_list_check() //checked changed at own discretion +{ + if ( !isDefined( level.destructible_equipment ) ) + { + level.destructible_equipment = []; + } + for ( i = 0; i < level.destructible_equipment.size; i++ ) + { + if ( !isDefined( level.destructible_equipment[ i ] ) ) + { + arrayremoveindex( level.destructible_equipment, i ); + } + } +} + +destructible_equipment_list_add( item ) //checked matches cerberus output +{ + destructible_equipment_list_check(); + level.destructible_equipment[ level.destructible_equipment.size ] = item; +} + +get_destructible_equipment_list() //checked matches cerberus output +{ + destructible_equipment_list_check(); + return level.destructible_equipment; +} + +equipment_disappear_fx( origin, fx, angles ) //checked matches cerberus output +{ + effect = level._equipment_disappear_fx; + if ( isDefined( fx ) ) + { + effect = fx; + } + if ( isDefined( angles ) ) + { + playfx( effect, origin, anglesToForward( angles ) ); + } + else + { + playfx( effect, origin ); + } + wait 1.1; +} + + + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_perks.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_perks.gsc new file mode 100644 index 0000000..fc9c614 --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_perks.gsc @@ -0,0 +1,3931 @@ +#include maps/mp/zombies/_zm; +#include maps/mp/zombies/_zm_perks; +#include maps/mp/_visionset_mgr; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/_demo; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_pers_upgrades_functions; +#include maps/mp/zombies/_zm_power; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; +#include maps/mp/zombies/_zm_magicbox; + +init() //checked partially changed to match cerberus output +{ + level.additionalprimaryweapon_limit = 3; + level.perk_purchase_limit = 4; + if ( !level.createfx_enabled ) + { + perks_register_clientfield(); //fixed + } + if ( !level.enable_magic ) + { + return; + } + initialize_custom_perk_arrays(); + perk_machine_spawn_init(); + vending_weapon_upgrade_trigger = []; + vending_triggers = getentarray( "zombie_vending", "targetname" ); + for ( i = 0; i < vending_triggers.size; i++ ) + { + if ( isDefined( vending_triggers[ i ].script_noteworthy ) && vending_triggers[ i ].script_noteworthy == "specialty_weapupgrade" ) + { + vending_weapon_upgrade_trigger[ vending_weapon_upgrade_trigger.size ] = vending_triggers[ i ]; + arrayremovevalue( vending_triggers, vending_triggers[ i ] ); + } + } + old_packs = getentarray( "zombie_vending_upgrade", "targetname" ); + i = 0; + for ( i = 0; i < old_packs.size; i++ ) + { + vending_weapon_upgrade_trigger[ vending_weapon_upgrade_trigger.size ] = old_packs[ i ]; + } + flag_init( "pack_machine_in_use" ); + if ( vending_triggers.size < 1 ) + { + return; + } + if ( vending_weapon_upgrade_trigger.size >= 1 ) + { + array_thread( vending_weapon_upgrade_trigger, ::vending_weapon_upgrade ); + } + level.machine_assets = []; + if ( !isDefined( level.custom_vending_precaching ) ) + { + level.custom_vending_precaching = ::default_vending_precaching; + } + [[ level.custom_vending_precaching ]](); + if ( !isDefined( level.packapunch_timeout ) ) + { + level.packapunch_timeout = 15; + } + set_zombie_var( "zombie_perk_cost", 2000 ); + set_zombie_var( "zombie_perk_juggernaut_health", 160 ); + set_zombie_var( "zombie_perk_juggernaut_health_upgrade", 190 ); + array_thread( vending_triggers, ::vending_trigger_think ); + array_thread( vending_triggers, ::electric_perks_dialog ); + + if ( is_true( level.zombiemode_using_doubletap_perk ) ) + { + level thread turn_doubletap_on(); + } + if ( is_true( level.zombiemode_using_marathon_perk ) ) + { + level thread turn_marathon_on(); + } + if ( is_true( level.zombiemode_using_juggernaut_perk ) ) + { + level thread turn_jugger_on(); + } + if ( is_true( level.zombiemode_using_revive_perk ) ) + { + level thread turn_revive_on(); + } + if ( is_true( level.zombiemode_using_sleightofhand_perk ) ) + { + level thread turn_sleight_on(); + } + if ( is_true( level.zombiemode_using_deadshot_perk ) ) + { + level thread turn_deadshot_on(); + } + if ( is_true( level.zombiemode_using_tombstone_perk ) ) + { + level thread turn_tombstone_on(); + } + if ( is_true( level.zombiemode_using_additionalprimaryweapon_perk ) ) + { + level thread turn_additionalprimaryweapon_on(); + } + if ( is_true( level.zombiemode_using_chugabud_perk ) ) + { + level thread turn_chugabud_on(); + } + if ( level._custom_perks.size > 0 ) + { + a_keys = getarraykeys( level._custom_perks ); + for ( i = 0; i < a_keys.size; i++ ) + { + if ( isdefined( level._custom_perks[ a_keys[ i ] ].perk_machine_thread ) ) + { + level thread [[ level._custom_perks[ a_keys[ i ] ].perk_machine_thread ]](); + } + } + } + if ( isDefined( level._custom_turn_packapunch_on ) ) + { + level thread [[ level._custom_turn_packapunch_on ]](); + } + else + { + level thread turn_packapunch_on(); + } + if ( isDefined( level.quantum_bomb_register_result_func ) ) + { + [[ level.quantum_bomb_register_result_func ]]( "give_nearest_perk", ::quantum_bomb_give_nearest_perk_result, 10, ::quantum_bomb_give_nearest_perk_validation ); + } + level thread perk_hostmigration(); + +} + +default_vending_precaching() //checked changed to match cerberus output +{ + if ( is_true( level.zombiemode_using_pack_a_punch ) ) + { + precacheitem( "zombie_knuckle_crack" ); + precachemodel( "p6_anim_zm_buildable_pap" ); + precachemodel( "p6_anim_zm_buildable_pap_on" ); + precachestring( &"ZOMBIE_PERK_PACKAPUNCH" ); + precachestring( &"ZOMBIE_PERK_PACKAPUNCH_ATT" ); + level._effect[ "packapunch_fx" ] = loadfx( "maps/zombie/fx_zombie_packapunch" ); + level.machine_assets[ "packapunch" ] = spawnstruct(); + level.machine_assets[ "packapunch" ].weapon = "zombie_knuckle_crack"; + level.machine_assets[ "packapunch" ].off_model = "p6_anim_zm_buildable_pap"; + level.machine_assets[ "packapunch" ].on_model = "p6_anim_zm_buildable_pap_on"; + } + if ( is_true( level.zombiemode_using_additionalprimaryweapon_perk ) ) + { + precacheitem( "zombie_perk_bottle_additionalprimaryweapon" ); + precacheshader( "specialty_additionalprimaryweapon_zombies" ); + precachemodel( "zombie_vending_three_gun" ); + precachemodel( "zombie_vending_three_gun_on" ); + precachestring( &"ZOMBIE_PERK_ADDITIONALWEAPONPERK" ); + level._effect[ "additionalprimaryweapon_light" ] = loadfx( "misc/fx_zombie_cola_arsenal_on" ); + level.machine_assets[ "additionalprimaryweapon" ] = spawnstruct(); + level.machine_assets[ "additionalprimaryweapon" ].weapon = "zombie_perk_bottle_additionalprimaryweapon"; + level.machine_assets[ "additionalprimaryweapon" ].off_model = "zombie_vending_three_gun"; + level.machine_assets[ "additionalprimaryweapon" ].on_model = "zombie_vending_three_gun_on"; + } + if ( is_true( level.zombiemode_using_deadshot_perk ) ) + { + precacheitem( "zombie_perk_bottle_deadshot" ); + precacheshader( "specialty_ads_zombies" ); + precachemodel( "zombie_vending_ads" ); + precachemodel( "zombie_vending_ads_on" ); + precachestring( &"ZOMBIE_PERK_DEADSHOT" ); + level._effect[ "deadshot_light" ] = loadfx( "misc/fx_zombie_cola_dtap_on" ); + level.machine_assets[ "deadshot" ] = spawnstruct(); + level.machine_assets[ "deadshot" ].weapon = "zombie_perk_bottle_deadshot"; + level.machine_assets[ "deadshot" ].off_model = "zombie_vending_ads"; + level.machine_assets[ "deadshot" ].on_model = "zombie_vending_ads_on"; + } + if ( is_true( level.zombiemode_using_doubletap_perk ) ) + { + precacheitem( "zombie_perk_bottle_doubletap" ); + precacheshader( "specialty_doubletap_zombies" ); + precachemodel( "zombie_vending_doubletap2" ); + precachemodel( "zombie_vending_doubletap2_on" ); + precachestring( &"ZOMBIE_PERK_DOUBLETAP" ); + level._effect[ "doubletap_light" ] = loadfx( "misc/fx_zombie_cola_dtap_on" ); + level.machine_assets[ "doubletap" ] = spawnstruct(); + level.machine_assets[ "doubletap" ].weapon = "zombie_perk_bottle_doubletap"; + level.machine_assets[ "doubletap" ].off_model = "zombie_vending_doubletap2"; + level.machine_assets[ "doubletap" ].on_model = "zombie_vending_doubletap2_on"; + } + if ( is_true( level.zombiemode_using_juggernaut_perk ) ) + { + precacheitem( "zombie_perk_bottle_jugg" ); + precacheshader( "specialty_juggernaut_zombies" ); + precachemodel( "zombie_vending_jugg" ); + precachemodel( "zombie_vending_jugg_on" ); + precachestring( &"ZOMBIE_PERK_JUGGERNAUT" ); + level._effect[ "jugger_light" ] = loadfx( "misc/fx_zombie_cola_jugg_on" ); + level.machine_assets[ "juggernog" ] = spawnstruct(); + level.machine_assets[ "juggernog" ].weapon = "zombie_perk_bottle_jugg"; + level.machine_assets[ "juggernog" ].off_model = "zombie_vending_jugg"; + level.machine_assets[ "juggernog" ].on_model = "zombie_vending_jugg_on"; + } + if ( is_true( level.zombiemode_using_marathon_perk ) ) + { + precacheitem( "zombie_perk_bottle_marathon" ); + precacheshader( "specialty_marathon_zombies" ); + precachemodel( "zombie_vending_marathon" ); + precachemodel( "zombie_vending_marathon_on" ); + precachestring( &"ZOMBIE_PERK_MARATHON" ); + level._effect[ "marathon_light" ] = loadfx( "maps/zombie/fx_zmb_cola_staminup_on" ); + level.machine_assets[ "marathon" ] = spawnstruct(); + level.machine_assets[ "marathon" ].weapon = "zombie_perk_bottle_marathon"; + level.machine_assets[ "marathon" ].off_model = "zombie_vending_marathon"; + level.machine_assets[ "marathon" ].on_model = "zombie_vending_marathon_on"; + } + if ( is_true( level.zombiemode_using_revive_perk ) ) + { + precacheitem( "zombie_perk_bottle_revive" ); + precacheshader( "specialty_quickrevive_zombies" ); + precachemodel( "zombie_vending_revive" ); + precachemodel( "zombie_vending_revive_on" ); + precachestring( &"ZOMBIE_PERK_QUICKREVIVE" ); + level._effect[ "revive_light" ] = loadfx( "misc/fx_zombie_cola_revive_on" ); + level._effect[ "revive_light_flicker" ] = loadfx( "maps/zombie/fx_zmb_cola_revive_flicker" ); + level.machine_assets[ "revive" ] = spawnstruct(); + level.machine_assets[ "revive" ].weapon = "zombie_perk_bottle_revive"; + level.machine_assets[ "revive" ].off_model = "zombie_vending_revive"; + level.machine_assets[ "revive" ].on_model = "zombie_vending_revive_on"; + } + if ( is_true( level.zombiemode_using_sleightofhand_perk ) ) + { + precacheitem( "zombie_perk_bottle_sleight" ); + precacheshader( "specialty_fastreload_zombies" ); + precachemodel( "zombie_vending_sleight" ); + precachemodel( "zombie_vending_sleight_on" ); + precachestring( &"ZOMBIE_PERK_FASTRELOAD" ); + level._effect[ "sleight_light" ] = loadfx( "misc/fx_zombie_cola_on" ); + level.machine_assets[ "speedcola" ] = spawnstruct(); + level.machine_assets[ "speedcola" ].weapon = "zombie_perk_bottle_sleight"; + level.machine_assets[ "speedcola" ].off_model = "zombie_vending_sleight"; + level.machine_assets[ "speedcola" ].on_model = "zombie_vending_sleight_on"; + } + if ( is_true( level.zombiemode_using_tombstone_perk ) ) + { + precacheitem( "zombie_perk_bottle_tombstone" ); + precacheshader( "specialty_tombstone_zombies" ); + precachemodel( "zombie_vending_tombstone" ); + precachemodel( "zombie_vending_tombstone_on" ); + precachemodel( "ch_tombstone1" ); + precachestring( &"ZOMBIE_PERK_TOMBSTONE" ); + level._effect[ "tombstone_light" ] = loadfx( "misc/fx_zombie_cola_on" ); + level.machine_assets[ "tombstone" ] = spawnstruct(); + level.machine_assets[ "tombstone" ].weapon = "zombie_perk_bottle_tombstone"; + level.machine_assets[ "tombstone" ].off_model = "zombie_vending_tombstone"; + level.machine_assets[ "tombstone" ].on_model = "zombie_vending_tombstone_on"; + } + if ( is_true( level.zombiemode_using_chugabud_perk ) ) + { + precacheitem( "zombie_perk_bottle_whoswho" ); + precacheshader( "specialty_quickrevive_zombies" ); + precachemodel( "p6_zm_vending_chugabud" ); + precachemodel( "p6_zm_vending_chugabud_on" ); + precachemodel( "ch_tombstone1" ); + precachestring( &"ZOMBIE_PERK_TOMBSTONE" ); + level._effect[ "tombstone_light" ] = loadfx( "misc/fx_zombie_cola_on" ); + level.machine_assets[ "whoswho" ] = spawnstruct(); + level.machine_assets[ "whoswho" ].weapon = "zombie_perk_bottle_whoswho"; + level.machine_assets[ "whoswho" ].off_model = "p6_zm_vending_chugabud"; + level.machine_assets[ "whoswho" ].on_model = "p6_zm_vending_chugabud_on"; + } + if ( level._custom_perks.size > 0 ) //changed + { + a_keys = getarraykeys( level._custom_perks ); + for ( i = 0; i < a_keys.size; i++ ) + { + if ( isdefined( level._custom_perks[ a_keys[ i ] ].precache_func ) ) + { + level [[ level._custom_perks[ a_keys[ i ] ].precache_func ]](); + } + } + } +} + +pap_weapon_move_in( trigger, origin_offset, angles_offset ) //checked matches cerberus output +{ + level endon( "Pack_A_Punch_off" ); + trigger endon( "pap_player_disconnected" ); + trigger.worldgun rotateto( self.angles + angles_offset + vectorScale( ( 0, 1, 0 ), 90 ), 0.35, 0, 0 ); + offsetdw = vectorScale( ( 1, 1, 1 ), 3 ); + if ( isDefined( trigger.worldgun.worldgundw ) ) + { + trigger.worldgun.worldgundw rotateto( self.angles + angles_offset + vectorScale( ( 0, 1, 0 ), 90 ), 0.35, 0, 0 ); + } + wait 0.5; + trigger.worldgun moveto( self.origin + origin_offset, 0.5, 0, 0 ); + if ( isDefined( trigger.worldgun.worldgundw ) ) + { + trigger.worldgun.worldgundw moveto( self.origin + origin_offset + offsetdw, 0.5, 0, 0 ); + } +} + +pap_weapon_move_out( trigger, origin_offset, interact_offset ) //checked matches cerberus output +{ + level endon( "Pack_A_Punch_off" ); + trigger endon( "pap_player_disconnected" ); + offsetdw = vectorScale( ( 1, 1, 1 ), 3 ); + if ( !isDefined( trigger.worldgun ) ) + { + return; + } + trigger.worldgun moveto( self.origin + interact_offset, 0.5, 0, 0 ); + if ( isDefined( trigger.worldgun.worldgundw ) ) + { + trigger.worldgun.worldgundw moveto( self.origin + interact_offset + offsetdw, 0.5, 0, 0 ); + } + wait 0.5; + if ( !isDefined( trigger.worldgun ) ) + { + return; + } + trigger.worldgun moveto( self.origin + origin_offset, level.packapunch_timeout, 0, 0 ); + if ( isDefined( trigger.worldgun.worldgundw ) ) + { + trigger.worldgun.worldgundw moveto( self.origin + origin_offset + offsetdw, level.packapunch_timeout, 0, 0 ); + } +} + +fx_ent_failsafe() //checked matches cerberus output +{ + wait 25; + self delete(); +} + +third_person_weapon_upgrade( current_weapon, upgrade_weapon, packa_rollers, perk_machine, trigger ) //checked matches cerberus output +{ + level endon( "Pack_A_Punch_off" ); + trigger endon( "pap_player_disconnected" ); + rel_entity = trigger.perk_machine; + origin_offset = ( 0, 0, 0 ); + angles_offset = ( 0, 0, 0 ); + origin_base = self.origin; + angles_base = self.angles; + if ( isDefined( rel_entity ) ) + { + if ( isDefined( level.pap_interaction_height ) ) + { + origin_offset = ( 0, 0, level.pap_interaction_height ); + } + else + { + origin_offset = vectorScale( ( 0, 0, 1 ), 35 ); + } + angles_offset = vectorScale( ( 0, 1, 0 ), 90 ); + origin_base = rel_entity.origin; + angles_base = rel_entity.angles; + } + else + { + rel_entity = self; + } + forward = anglesToForward( angles_base + angles_offset ); + interact_offset = origin_offset + ( forward * -25 ); + if ( !isDefined( perk_machine.fx_ent ) ) + { + perk_machine.fx_ent = spawn( "script_model", origin_base + origin_offset + ( 0, 1, -34 ) ); + perk_machine.fx_ent.angles = angles_base + angles_offset; + perk_machine.fx_ent setmodel( "tag_origin" ); + perk_machine.fx_ent linkto( perk_machine ); + } + if ( isDefined( level._effect[ "packapunch_fx" ] ) ) + { + fx = playfxontag( level._effect[ "packapunch_fx" ], perk_machine.fx_ent, "tag_origin" ); + } + offsetdw = vectorScale( ( 1, 1, 1 ), 3 ); + weoptions = self maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( current_weapon ); + trigger.worldgun = spawn_weapon_model( current_weapon, undefined, origin_base + interact_offset, self.angles, weoptions ); + worldgundw = undefined; + if ( maps/mp/zombies/_zm_magicbox::weapon_is_dual_wield( current_weapon ) ) + { + worldgundw = spawn_weapon_model( current_weapon, maps/mp/zombies/_zm_magicbox::get_left_hand_weapon_model_name( current_weapon ), origin_base + interact_offset + offsetdw, self.angles, weoptions ); + } + trigger.worldgun.worldgundw = worldgundw; + if ( isDefined( level.custom_pap_move_in ) ) + { + perk_machine [[ level.custom_pap_move_in ]]( trigger, origin_offset, angles_offset, perk_machine ); + } + else + { + perk_machine pap_weapon_move_in( trigger, origin_offset, angles_offset ); + } + self playsound( "zmb_perks_packa_upgrade" ); + if ( isDefined( perk_machine.wait_flag ) ) + { + perk_machine.wait_flag rotateto( perk_machine.wait_flag.angles + vectorScale( ( 1, 0, 0 ), 179 ), 0.25, 0, 0 ); + } + wait 0.35; + trigger.worldgun delete(); + if ( isDefined( worldgundw ) ) + { + worldgundw delete(); + } + wait 3; + if ( isDefined( self ) ) + { + self playsound( "zmb_perks_packa_ready" ); + } + else + { + return; + } + upoptions = self maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( upgrade_weapon ); + trigger.current_weapon = current_weapon; + trigger.upgrade_name = upgrade_weapon; + trigger.worldgun = spawn_weapon_model( upgrade_weapon, undefined, origin_base + origin_offset, angles_base + angles_offset + vectorScale( ( 0, 1, 0 ), 90 ), upoptions ); + worldgundw = undefined; + if ( maps/mp/zombies/_zm_magicbox::weapon_is_dual_wield( upgrade_weapon ) ) + { + worldgundw = spawn_weapon_model( upgrade_weapon, maps/mp/zombies/_zm_magicbox::get_left_hand_weapon_model_name( upgrade_weapon ), origin_base + origin_offset + offsetdw, angles_base + angles_offset + vectorScale( ( 0, -1, 0 ), 90 ), upoptions ); + } + trigger.worldgun.worldgundw = worldgundw; + if ( isDefined( perk_machine.wait_flag ) ) + { + perk_machine.wait_flag rotateto( perk_machine.wait_flag.angles - vectorScale( ( 1, 0, 0 ), 179 ), 0.25, 0, 0 ); + } + if ( isDefined( level.custom_pap_move_out ) ) + { + rel_entity thread [[ level.custom_pap_move_out ]]( trigger, origin_offset, interact_offset ); + } + else + { + rel_entity thread pap_weapon_move_out( trigger, origin_offset, interact_offset ); + } + return trigger.worldgun; +} + +can_pack_weapon( weaponname ) //checked did not match cebrerus output changed at own discretion +{ + if ( weaponname == "riotshield_zm" ) + { + return 0; + } + if ( flag( "pack_machine_in_use" ) ) + { + return 1; + } + weaponname = self get_nonalternate_weapon( weaponname ); + if ( !maps/mp/zombies/_zm_weapons::is_weapon_or_base_included( weaponname ) ) + { + return 0; + } + if ( !self maps/mp/zombies/_zm_weapons::can_upgrade_weapon( weaponname ) ) + { + return 0; + } + return 1; +} + +player_use_can_pack_now() //checked changed to match cerberus output +{ + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || is_true( self.intermission ) || self isthrowinggrenade() ) + { + return 0; + } + if ( !self can_buy_weapon() ) + { + return 0; + } + if ( self hacker_active() ) + { + return 0; + } + if ( !self can_pack_weapon( self getcurrentweapon() ) ) + { + return 0; + } + return 1; +} + +vending_machine_trigger_think() //changed 3/30/20 4:17 pm //checked matches cerberus output +{ + self endon("death"); + self endon("Pack_A_Punch_off"); + while( 1 ) + { + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( isdefined( self.pack_player ) && self.pack_player != players[ i ] || !players[ i ] player_use_can_pack_now() ) + { + self setinvisibletoplayer( players[ i ], 1 ); + i++; + continue; + } + self setinvisibletoplayer( players[ i ], 0 ); + i++; + } + wait 0.1; + } +} + +vending_weapon_upgrade() //checked matches cerberus output +{ + level endon( "Pack_A_Punch_off" ); + wait 0.01; + perk_machine = getent( self.target, "targetname" ); + self.perk_machine = perk_machine; + perk_machine_sound = getentarray( "perksacola", "targetname" ); + packa_rollers = spawn( "script_origin", self.origin ); + packa_timer = spawn( "script_origin", self.origin ); + packa_rollers linkto( self ); + packa_timer linkto( self ); + if ( isDefined( perk_machine.target ) ) + { + perk_machine.wait_flag = getent( perk_machine.target, "targetname" ); + } + pap_is_buildable = self is_buildable(); + if ( pap_is_buildable ) + { + self trigger_off(); + perk_machine hide(); + if ( isDefined( perk_machine.wait_flag ) ) + { + perk_machine.wait_flag hide(); + } + wait_for_buildable( "pap" ); + self trigger_on(); + perk_machine show(); + if ( isDefined( perk_machine.wait_flag ) ) + { + perk_machine.wait_flag show(); + } + } + self usetriggerrequirelookat(); + self sethintstring( &"ZOMBIE_NEED_POWER" ); + self setcursorhint( "HINT_NOICON" ); + power_off = !self maps/mp/zombies/_zm_power::pap_is_on(); + if ( power_off ) + { + pap_array = []; + pap_array[ 0 ] = perk_machine; + level thread do_initial_power_off_callback( pap_array, "packapunch" ); + level waittill( "Pack_A_Punch_on" ); + } + self enable_trigger(); + if ( isDefined( level.machine_assets[ "packapunch" ].power_on_callback ) ) + { + perk_machine thread [[ level.machine_assets[ "packapunch" ].power_on_callback ]](); + } + self thread vending_machine_trigger_think(); + perk_machine playloopsound( "zmb_perks_packa_loop" ); + self thread shutoffpapsounds( perk_machine, packa_rollers, packa_timer ); + self thread vending_weapon_upgrade_cost(); + for ( ;; ) + { + self.pack_player = undefined; + self waittill( "trigger", player ); + index = maps/mp/zombies/_zm_weapons::get_player_index( player ); + current_weapon = player getcurrentweapon(); + current_weapon = player maps/mp/zombies/_zm_weapons::switch_from_alt_weapon( current_weapon ); + if ( isDefined( level.custom_pap_validation ) ) + { + valid = self [[ level.custom_pap_validation ]]( player ); + if ( !valid ) + { + continue; + } + } + if ( player maps/mp/zombies/_zm_magicbox::can_buy_weapon() && !player maps/mp/zombies/_zm_laststand::player_is_in_laststand() && !is_true( player.intermission ) || player isthrowinggrenade() && !player maps/mp/zombies/_zm_weapons::can_upgrade_weapon( current_weapon ) ) + { + wait 0.1; + continue; + } + if ( is_true( level.pap_moving ) ) + { + continue; + } + if ( player isswitchingweapons() ) + { + wait 0.1; + if ( player isswitchingweapons() ) + { + continue; + } + } + if ( !maps/mp/zombies/_zm_weapons::is_weapon_or_base_included( current_weapon ) ) + { + continue; + } + + current_cost = self.cost; + player.restore_ammo = undefined; + player.restore_clip = undefined; + player.restore_stock = undefined; + player_restore_clip_size = undefined; + player.restore_max = undefined; + upgrade_as_attachment = will_upgrade_weapon_as_attachment( current_weapon ); + if ( upgrade_as_attachment ) + { + current_cost = self.attachment_cost; + player.restore_ammo = 1; + player.restore_clip = player getweaponammoclip( current_weapon ); + player.restore_clip_size = weaponclipsize( current_weapon ); + player.restore_stock = player getweaponammostock( current_weapon ); + player.restore_max = weaponmaxammo( current_weapon ); + } + if ( player maps/mp/zombies/_zm_pers_upgrades_functions::is_pers_double_points_active() ) + { + current_cost = player maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_double_points_cost( current_cost ); + } + if ( player.score < current_cost ) + { + self playsound( "deny" ); + if ( isDefined( level.custom_pap_deny_vo_func ) ) + { + player [[ level.custom_pap_deny_vo_func ]](); + } + else + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "perk_deny", undefined, 0 ); + } + continue; + } + + self.pack_player = player; + flag_set( "pack_machine_in_use" ); + maps/mp/_demo::bookmark( "zm_player_use_packapunch", getTime(), player ); + player maps/mp/zombies/_zm_stats::increment_client_stat( "use_pap" ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "use_pap" ); + self thread destroy_weapon_in_blackout( player ); + self thread destroy_weapon_on_disconnect( player ); + player maps/mp/zombies/_zm_score::minus_to_player_score( current_cost, 1 ); + sound = "evt_bottle_dispense"; + playsoundatposition( sound, self.origin ); + self thread maps/mp/zombies/_zm_audio::play_jingle_or_stinger( "mus_perks_packa_sting" ); + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", "upgrade_wait" ); + self disable_trigger(); + if ( !is_true( upgrade_as_attachment ) ) + { + player thread do_player_general_vox( "general", "pap_wait", 10, 100 ); + } + else + { + player thread do_player_general_vox( "general", "pap_wait2", 10, 100 ); + } + player thread do_knuckle_crack(); + self.current_weapon = current_weapon; + upgrade_name = maps/mp/zombies/_zm_weapons::get_upgrade_weapon( current_weapon, upgrade_as_attachment ); + player third_person_weapon_upgrade( current_weapon, upgrade_name, packa_rollers, perk_machine, self ); + self enable_trigger(); + self sethintstring( &"ZOMBIE_GET_UPGRADED" ); + if ( isDefined( player ) ) + { + self setinvisibletoall(); + self setvisibletoplayer( player ); + self thread wait_for_player_to_take( player, current_weapon, packa_timer, upgrade_as_attachment ); + } + self thread wait_for_timeout( current_weapon, packa_timer, player ); + self waittill_any( "pap_timeout", "pap_taken", "pap_player_disconnected" ); + self.current_weapon = ""; + if ( isDefined( self.worldgun ) && isDefined( self.worldgun.worldgundw ) ) + { + self.worldgun.worldgundw delete(); + } + if ( isDefined( self.worldgun ) ) + { + self.worldgun delete(); + } + if ( is_true( level.zombiemode_reusing_pack_a_punch ) ) + { + self sethintstring( &"ZOMBIE_PERK_PACKAPUNCH_ATT", self.cost ); + } + else + { + self sethintstring( &"ZOMBIE_PERK_PACKAPUNCH", self.cost ); + } + self setvisibletoall(); + self.pack_player = undefined; + flag_clear( "pack_machine_in_use" ); + } +} + +shutoffpapsounds( ent1, ent2, ent3 ) //checked matches cerberus output +{ + while ( 1 ) + { + level waittill( "Pack_A_Punch_off" ); + level thread turnonpapsounds( ent1 ); + ent1 stoploopsound( 0.1 ); + ent2 stoploopsound( 0.1 ); + ent3 stoploopsound( 0.1 ); + } +} + +turnonpapsounds( ent ) //checked 3/30/20 4:18 pm //checked matches cerberus output +{ + level waittill( "Pack_A_Punch_on" ); + ent playloopsound( "zmb_perks_packa_loop" ); +} + +vending_weapon_upgrade_cost() //checked 3/30/20 4:19 pm //checked matches cerberus output +{ + level endon( "Pack_A_Punch_off" ); + while ( 1 ) + { + self.cost = 5000; + self.attachment_cost = 2000; + if ( is_true( level.zombiemode_reusing_pack_a_punch ) ) + { + self sethintstring( &"ZOMBIE_PERK_PACKAPUNCH_ATT", self.cost ); + } + else + { + self sethintstring( &"ZOMBIE_PERK_PACKAPUNCH", self.cost ); + } + level waittill( "powerup bonfire sale" ); + self.cost = 1000; + self.attachment_cost = 1000; + if ( is_true( level.zombiemode_reusing_pack_a_punch ) ) + { + self sethintstring( &"ZOMBIE_PERK_PACKAPUNCH_ATT", self.cost ); + } + else + { + self sethintstring( &"ZOMBIE_PERK_PACKAPUNCH", self.cost ); + } + level waittill( "bonfire_sale_off" ); + } +} + +wait_for_player_to_take( player, weapon, packa_timer, upgrade_as_attachment ) //changed 3/30/20 4:22 pm //checked matches cerberus output +{ + current_weapon = self.current_weapon; + upgrade_name = self.upgrade_name; + /* +/# + assert( isDefined( current_weapon ), "wait_for_player_to_take: weapon does not exist" ); +#/ +/# + assert( isDefined( upgrade_name ), "wait_for_player_to_take: upgrade_weapon does not exist" ); +#/ + */ + upgrade_weapon = upgrade_name; + self endon( "pap_timeout" ); + level endon( "Pack_A_Punch_off" ); + while ( 1 ) + { + packa_timer playloopsound( "zmb_perks_packa_ticktock" ); + self waittill( "trigger", trigger_player ); + if ( is_true( level.pap_grab_by_anyone ) ) + { + player = trigger_player; + } + + packa_timer stoploopsound( 0.05 ); + if ( trigger_player == player ) //working + { + player maps/mp/zombies/_zm_stats::increment_client_stat( "pap_weapon_grabbed" ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "pap_weapon_grabbed" ); + current_weapon = player getcurrentweapon(); + /* +/# + if ( current_weapon == "none" ) + { + iprintlnbold( "WEAPON IS NONE, PACKAPUNCH RETRIEVAL DENIED" ); +#/ + } + */ + if ( is_player_valid( player ) && !player.is_drinking && !is_placeable_mine( current_weapon ) && !is_equipment( current_weapon ) && level.revive_tool != current_weapon && current_weapon != "none" && !player hacker_active() ) + { + maps/mp/_demo::bookmark( "zm_player_grabbed_packapunch", getTime(), player ); + self notify( "pap_taken" ); + player notify( "pap_taken" ); + player.pap_used = 1; + if ( !is_true( upgrade_as_attachment ) ) + { + player thread do_player_general_vox( "general", "pap_arm", 15, 100 ); + } + else + { + player thread do_player_general_vox( "general", "pap_arm2", 15, 100 ); + } + weapon_limit = get_player_weapon_limit( player ); + player maps/mp/zombies/_zm_weapons::take_fallback_weapon(); + primaries = player getweaponslistprimaries(); + if ( isDefined( primaries ) && primaries.size >= weapon_limit ) + { + player maps/mp/zombies/_zm_weapons::weapon_give( upgrade_weapon ); + } + else + { + player giveweapon( upgrade_weapon, 0, player maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( upgrade_weapon ) ); + player givestartammo( upgrade_weapon ); + } + player switchtoweapon( upgrade_weapon ); + if ( is_true( player.restore_ammo ) ) + { + new_clip = player.restore_clip + ( weaponclipsize( upgrade_weapon ) - player.restore_clip_size ); + new_stock = player.restore_stock + ( weaponmaxammo( upgrade_weapon ) - player.restore_max ); + player setweaponammostock( upgrade_weapon, new_stock ); + player setweaponammoclip( upgrade_weapon, new_clip ); + } + player.restore_ammo = undefined; + player.restore_clip = undefined; + player.restore_stock = undefined; + player.restore_max = undefined; + player.restore_clip_size = undefined; + player maps/mp/zombies/_zm_weapons::play_weapon_vo( upgrade_weapon ); + return; + } + } + //wait 0.05; + } +} + +wait_for_timeout( weapon, packa_timer, player ) //checked //checked matches cerberus output +{ + self endon( "pap_taken" ); + self endon( "pap_player_disconnected" ); + self thread wait_for_disconnect( player ); + wait level.packapunch_timeout; + self notify( "pap_timeout" ); + packa_timer stoploopsound( 0.05 ); + packa_timer playsound( "zmb_perks_packa_deny" ); + maps/mp/zombies/_zm_weapons::unacquire_weapon_toggle( weapon ); + if ( isDefined( player ) ) + { + player maps/mp/zombies/_zm_stats::increment_client_stat( "pap_weapon_not_grabbed" ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "pap_weapon_not_grabbed" ); + } +} + +wait_for_disconnect( player ) //checked //checked matches cerberus output +{ + self endon( "pap_taken" ); + self endon( "pap_timeout" ); + name = player.name; + while ( isDefined( player ) ) + { + wait 0.1; + } + self notify( "pap_player_disconnected" ); +} + +destroy_weapon_on_disconnect( player ) //checked //checked matches cerberus output +{ + self endon( "pap_timeout" ); + self endon( "pap_taken" ); + level endon( "Pack_A_Punch_off" ); + player waittill( "disconnect" ); + if ( isDefined( self.worldgun ) ) + { + if ( isDefined( self.worldgun.worldgundw ) ) + { + self.worldgun.worldgundw delete(); + } + self.worldgun delete(); + } +} + +destroy_weapon_in_blackout( player ) //checked //checked matches cerberus output +{ + self endon( "pap_timeout" ); + self endon( "pap_taken" ); + self endon( "pap_player_disconnected" ); + level waittill( "Pack_A_Punch_off" ); + if ( isDefined( self.worldgun ) ) + { + self.worldgun rotateto( self.worldgun.angles + ( randomint( 90 ) - 45, 0, randomint( 360 ) - 180 ), 1.5, 0, 0 ); + player playlocalsound( level.zmb_laugh_alias ); + wait 1.5; + if ( isDefined( self.worldgun.worldgundw ) ) + { + self.worldgun.worldgundw delete(); + } + self.worldgun delete(); + } +} + +do_knuckle_crack() //checked //checked matches cerberus output +{ + self endon( "disconnect" ); + gun = self upgrade_knuckle_crack_begin(); + self waittill_any( "fake_death", "death", "player_downed", "weapon_change_complete" ); + self upgrade_knuckle_crack_end( gun ); +} + +upgrade_knuckle_crack_begin() //checked matches cerberus output +{ + self increment_is_drinking(); + self disable_player_move_states( 1 ); + primaries = self getweaponslistprimaries(); + gun = self getcurrentweapon(); + weapon = level.machine_assets[ "packapunch" ].weapon; + if ( gun != "none" && !is_placeable_mine( gun ) && !is_equipment( gun ) ) + { + self notify( "zmb_lost_knife" ); + self takeweapon( gun ); + } + else + { + return; + } + self giveweapon( weapon ); + self switchtoweapon( weapon ); + return gun; +} + +upgrade_knuckle_crack_end( gun ) //changed //checked matches cerberus output +{ +/* +/# + assert( !is_zombie_perk_bottle( gun ) ); +#/ +/# + assert( gun != level.revive_tool ); +#/ +*/ + self enable_player_move_states(); + weapon = level.machine_assets[ "packapunch" ].weapon; + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || is_true( self.intermission ) ) + { + self takeweapon( weapon ); + return; + } + self decrement_is_drinking(); + self takeweapon( weapon ); + primaries = self getweaponslistprimaries(); + if ( self.is_drinking > 0 ) + { + return; + } + else if ( isDefined( primaries ) && primaries.size > 0 ) + { + self switchtoweapon( primaries[ 0 ] ); + } + else if ( self hasweapon( level.laststandpistol ) ) + { + self switchtoweapon( level.laststandpistol ); + } + else + { + self maps/mp/zombies/_zm_weapons::give_fallback_weapon(); + } +} + +turn_packapunch_on() //checked changed to match cerberus output +{ + vending_weapon_upgrade_trigger = getentarray( "specialty_weapupgrade", "script_noteworthy" ); + level.pap_triggers = vending_weapon_upgrade_trigger; + for ( i = 0; i < vending_weapon_upgrade_trigger.size; i++ ) + { + perk = getent( vending_weapon_upgrade_trigger[ i ].target, "targetname" ); + if ( isDefined( perk ) ) + { + perk setmodel( level.machine_assets[ "packapunch" ].off_model ); + } + } + for ( ;; ) + { + level waittill( "Pack_A_Punch_on" ); + for ( i = 0; i < vending_weapon_upgrade_trigger.size; i++ ) + { + perk = getent( vending_weapon_upgrade_trigger[ i ].target, "targetname" ); + if ( isDefined( perk ) ) + { + perk thread activate_packapunch(); + } + } + level waittill( "Pack_A_Punch_off" ); + for ( i = 0; i < vending_weapon_upgrade_trigger.size; i++ ) + { + perk = getent( vending_weapon_upgrade_trigger[ i ].target, "targetname" ); + if ( isDefined( perk ) ) + { + perk thread deactivate_packapunch(); + } + } + } +} + +activate_packapunch() //checked matches cerberus output +{ + self setmodel( level.machine_assets[ "packapunch" ].on_model ); + self playsound( "zmb_perks_power_on" ); + self vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + timer = 0; + duration = 0.05; +} + +deactivate_packapunch() //checked matches cerberus output +{ + self setmodel( level.machine_assets[ "packapunch" ].off_model ); +} + +do_initial_power_off_callback( machine_array, perkname ) //checked matches cerberus output +{ + if ( !isDefined( level.machine_assets[ perkname ] ) ) + { + /* +/# + println( "Error: doing setup for a machine with no level.machine_assets! Check your perk initialization!" ); +#/ + */ + return; + } + if ( !isDefined( level.machine_assets[ perkname ].power_off_callback ) ) + { + return; + } + wait 0.05; + array_thread( machine_array, level.machine_assets[ perkname ].power_off_callback ); +} + +turn_sleight_on() //checked changed to match cerberus output +{ + while ( 1 ) + { + machine = getentarray( "vending_sleight", "targetname" ); + machine_triggers = getentarray( "vending_sleight", "target" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "speedcola" ].off_model ); + } + level thread do_initial_power_off_callback( machine, "speedcola" ); + array_thread( machine_triggers, ::set_power_on, 0 ); + level waittill( "sleight_on" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "speedcola" ].on_model ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "sleight_light" ); + machine[ i ] thread play_loop_on_machine(); + } + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "speedcola" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "speedcola" ].power_on_callback ); + } + level notify( "specialty_fastreload_power_on" ); + level waittill( "sleight_off" ); + array_thread( machine, ::turn_perk_off ); + if ( isDefined( level.machine_assets[ "speedcola" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "speedcola" ].power_off_callback ); + } + } +} + +use_solo_revive() //checked matches cerberus output +{ + if ( isDefined( level.using_solo_revive ) ) + { + return level.using_solo_revive; + } + players = get_players(); + solo_mode = 0; + if ( players.size == 1 || is_true( level.force_solo_quick_revive ) ) + { + solo_mode = 1; + } + level.using_solo_revive = solo_mode; + return solo_mode; +} + +turn_revive_on() //checked partially changed to match cerberus output +{ + level endon( "stop_quickrevive_logic" ); + machine = getentarray( "vending_revive", "targetname" ); + machine_triggers = getentarray( "vending_revive", "target" ); + machine_model = undefined; + machine_clip = undefined; + if ( !is_true( level.zombiemode_using_revive_perk ) ) + { + return; + } + flag_wait( "start_zombie_round_logic" ); + players = get_players(); + solo_mode = 0; + if ( use_solo_revive() ) + { + solo_mode = 1; + } + start_state = 0; + start_state = solo_mode; + while ( 1 ) + { + machine = getentarray( "vending_revive", "targetname" ); + machine_triggers = getentarray( "vending_revive", "target" ); + for ( i = 0; i < machine.size; i++ ) + { + if ( flag_exists( "solo_game" ) && flag_exists( "solo_revive" ) && flag( "solo_game" ) && flag( "solo_revive" ) ) + { + machine[ i ] hide(); + } + machine[ i ] setmodel( level.machine_assets[ "revive" ].off_model ); + if ( isDefined( level.quick_revive_final_pos ) ) + { + level.quick_revive_default_origin = level.quick_revive_final_pos; + } + if ( !isDefined( level.quick_revive_default_origin ) ) + { + level.quick_revive_default_origin = machine[ i ].origin; + level.quick_revive_default_angles = machine[ i ].angles; + } + level.quick_revive_machine = machine[ i ]; + } + array_thread( machine_triggers, ::set_power_on, 0 ); + if ( !is_true( start_state ) ) + { + level waittill( "revive_on" ); + } + start_state = 0; + i = 0; + while ( i < machine.size ) + { + if ( isDefined( machine[ i ].classname ) && machine[ i ].classname == "script_model" ) + { + if ( isDefined( machine[ i ].script_noteworthy ) && machine[ i ].script_noteworthy == "clip" ) + { + machine_clip = machine[ i ]; + i++; + continue; + } + machine[ i ] setmodel( level.machine_assets[ "revive" ].on_model ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + machine_model = machine[ i ]; + machine[ i ] thread perk_fx( "revive_light" ); + machine[ i ] notify( "stop_loopsound" ); + machine[ i ] thread play_loop_on_machine(); + if ( isDefined( machine_triggers[ i ] ) ) + { + machine_clip = machine_triggers[ i ].clip; + } + if ( isDefined( machine_triggers[ i ] ) ) + { + blocker_model = machine_triggers[ i ].blocker_model; + } + } + i++; + } + wait_network_frame(); + if ( solo_mode && isDefined( machine_model ) && !is_true( machine_model.ishidden ) ) + { + machine_model thread revive_solo_fx( machine_clip, blocker_model ); + } + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "revive" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "revive" ].power_on_callback ); + } + level notify( "specialty_quickrevive_power_on" ); + if ( isDefined( machine_model ) ) + { + machine_model.ishidden = 0; + } + notify_str = level waittill_any_return( "revive_off", "revive_hide" ); + should_hide = 0; + if ( notify_str == "revive_hide" ) + { + should_hide = 1; + } + if ( isDefined( level.machine_assets[ "revive" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "revive" ].power_off_callback ); + } + for ( i = 0; i < machine.size; i++ ) + { + if ( isDefined( machine[ i ].classname ) && machine[ i ].classname == "script_model" ) + { + machine[ i ] turn_perk_off( should_hide ); + } + } + } +} + +revive_solo_fx( machine_clip, blocker_model ) //checked matches cerberus output +{ + if ( level flag_exists( "solo_revive" ) && flag( "solo_revive" ) && !flag( "solo_game" ) ) + { + return; + } + if ( isDefined( machine_clip ) ) + { + level.quick_revive_machine_clip = machine_clip; + } + if ( !isDefined( level.solo_revive_init ) ) + { + level.solo_revive_init = 1; + flag_init( "solo_revive" ); + } + level notify( "revive_solo_fx" ); + level endon( "revive_solo_fx" ); + self endon( "death" ); + flag_wait( "solo_revive" ); + if ( isDefined( level.revive_solo_fx_func ) ) + { + level thread [[ level.revive_solo_fx_func ]](); + } + wait 2; + self playsound( "zmb_box_move" ); + playsoundatposition( "zmb_whoosh", self.origin ); + if ( isDefined( self._linked_ent ) ) + { + self unlink(); + } + self moveto( self.origin + vectorScale( ( 0, 0, 1 ), 40 ), 3 ); + if ( isDefined( level.custom_vibrate_func ) ) + { + [[ level.custom_vibrate_func ]]( self ); + } + else + { + direction = self.origin; + direction = ( direction[ 1 ], direction[ 0 ], 0 ); + if ( direction[ 1 ] < 0 || direction[ 0 ] > 0 && direction[ 1 ] > 0 ) + { + direction = ( direction[ 0 ], direction[ 1 ] * -1, 0 ); + } + else + { + if ( direction[ 0 ] < 0 ) + { + direction = ( direction[ 0 ] * -1, direction[ 1 ], 0 ); + } + } + self vibrate( direction, 10, 0.5, 5 ); + } + self waittill( "movedone" ); + playfx( level._effect[ "poltergeist" ], self.origin ); + playsoundatposition( "zmb_box_poof", self.origin ); + level clientnotify( "drb" ); + if ( isDefined( self.fx ) ) + { + self.fx unlink(); + self.fx delete(); + } + if ( isDefined( machine_clip ) ) + { + machine_clip trigger_off(); + machine_clip connectpaths(); + } + if ( isDefined( blocker_model ) ) + { + blocker_model show(); + } + level notify( "revive_hide" ); +} + +turn_jugger_on() //checked changed to match cerberus output +{ + while ( 1 ) + { + machine = getentarray( "vending_jugg", "targetname" ); + machine_triggers = getentarray( "vending_jugg", "target" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "juggernog" ].off_model ); + } + level thread do_initial_power_off_callback( machine, "juggernog" ); + array_thread( machine_triggers, ::set_power_on, 0 ); + level waittill( "juggernog_on" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "juggernog" ].on_model ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "jugger_light" ); + machine[ i ] thread play_loop_on_machine(); + } + level notify( "specialty_armorvest_power_on" ); + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "juggernog" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "juggernog" ].power_on_callback ); + } + level waittill( "juggernog_off" ); + if ( isDefined( level.machine_assets[ "juggernog" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "juggernog" ].power_off_callback ); + } + array_thread( machine, ::turn_perk_off ); + } +} + +turn_doubletap_on() //checked changed to match cerberus output +{ + while ( 1 ) + { + machine = getentarray( "vending_doubletap", "targetname" ); + machine_triggers = getentarray( "vending_doubletap", "target" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "doubletap" ].off_model ); + } + level thread do_initial_power_off_callback( machine, "doubletap" ); + array_thread( machine_triggers, ::set_power_on, 0 ); + level waittill( "doubletap_on" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "doubletap" ].on_model ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "doubletap_light" ); + machine[ i ] thread play_loop_on_machine(); + } + level notify( "specialty_rof_power_on" ); + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "doubletap" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "doubletap" ].power_on_callback ); + } + level waittill( "doubletap_off" ); + if ( isDefined( level.machine_assets[ "doubletap" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "doubletap" ].power_off_callback ); + } + array_thread( machine, ::turn_perk_off ); + } +} + +turn_marathon_on() //checked changed to match cerberus output +{ + while ( 1 ) + { + machine = getentarray( "vending_marathon", "targetname" ); + machine_triggers = getentarray( "vending_marathon", "target" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "marathon" ].off_model ); + } + array_thread( machine_triggers, ::set_power_on, 0 ); + level thread do_initial_power_off_callback( machine, "marathon" ); + level waittill( "marathon_on" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "marathon" ].on_model ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "marathon_light" ); + machine[ i ] thread play_loop_on_machine(); + i++; + } + level notify( "specialty_longersprint_power_on" ); + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "marathon" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "marathon" ].power_on_callback ); + } + level waittill( "marathon_off" ); + if ( isDefined( level.machine_assets[ "marathon" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "marathon" ].power_off_callback ); + } + array_thread( machine, ::turn_perk_off ); + } +} + +turn_deadshot_on() //checked changed to match cerberus output +{ + while ( 1 ) + { + machine = getentarray( "vending_deadshot_model", "targetname" ); + machine_triggers = getentarray( "vending_deadshot", "target" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "deadshot" ].off_model ); + } + level thread do_initial_power_off_callback( machine, "deadshot" ); + array_thread( machine_triggers, ::set_power_on, 0 ); + level waittill( "deadshot_on" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "deadshot" ].on_model ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "deadshot_light" ); + machine[ i ] thread play_loop_on_machine(); + } + level notify( "specialty_deadshot_power_on" ); + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "deadshot" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "deadshot" ].power_on_callback ); + } + level waittill( "deadshot_off" ); + if ( isDefined( level.machine_assets[ "deadshot" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "deadshot" ].power_off_callback ); + } + array_thread( machine, ::turn_perk_off ); + } +} + +turn_tombstone_on() //checked changed to match cerberus output +{ + level endon( "tombstone_removed" ); + while ( 1 ) + { + machine = getentarray( "vending_tombstone", "targetname" ); + machine_triggers = getentarray( "vending_tombstone", "target" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "tombstone" ].off_model ); + } + level thread do_initial_power_off_callback( machine, "tombstone" ); + array_thread( machine_triggers, ::set_power_on, 0 ); + level waittill( "tombstone_on" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "tombstone" ].on_model ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "tombstone_light" ); + machine[ i ] thread play_loop_on_machine(); + } + level notify( "specialty_scavenger_power_on" ); + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "tombstone" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "tombstone" ].power_on_callback ); + } + level waittill( "tombstone_off" ); + if ( isDefined( level.machine_assets[ "tombstone" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "tombstone" ].power_off_callback ); + } + array_thread( machine, ::turn_perk_off ); + players = get_players(); + foreach ( player in players ) + { + player.hasperkspecialtytombstone = undefined; + } + } +} + +turn_additionalprimaryweapon_on() //checked changed to match cerberus output +{ + while ( 1 ) + { + machine = getentarray( "vending_additionalprimaryweapon", "targetname" ); + machine_triggers = getentarray( "vending_additionalprimaryweapon", "target" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "additionalprimaryweapon" ].off_model ); + } + level thread do_initial_power_off_callback( machine, "additionalprimaryweapon" ); + array_thread( machine_triggers, ::set_power_on, 0 ); + level waittill( "additionalprimaryweapon_on" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "additionalprimaryweapon" ].on_model ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "additionalprimaryweapon_light" ); + machine[ i ] thread play_loop_on_machine(); + } + level notify( "specialty_additionalprimaryweapon_power_on" ); + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "additionalprimaryweapon" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "additionalprimaryweapon" ].power_on_callback ); + } + level waittill( "additionalprimaryweapon_off" ); + if ( isDefined( level.machine_assets[ "additionalprimaryweapon" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "additionalprimaryweapon" ].power_off_callback ); + } + array_thread( machine, ::turn_perk_off ); + } +} + +turn_chugabud_on() //checked changed to match cerberus output +{ + maps/mp/zombies/_zm_chugabud::init(); + if ( isDefined( level.vsmgr_prio_visionset_zm_whos_who ) ) + { + maps/mp/_visionset_mgr::vsmgr_register_info( "visionset", "zm_whos_who", 5000, level.vsmgr_prio_visionset_zm_whos_who, 1, 1 ); + } + while ( 1 ) + { + machine = getentarray( "vending_chugabud", "targetname" ); + machine_triggers = getentarray( "vending_chugabud", "target" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "whoswho" ].off_model ); + } + level thread do_initial_power_off_callback( machine, "whoswho" ); + array_thread( machine_triggers, ::set_power_on, 0 ); + level waittill( "chugabud_on" ); + for ( i = 0; i < machine.size; i++ ) + { + machine[ i ] setmodel( level.machine_assets[ "whoswho" ].on_model ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "tombstone_light" ); + machine[ i ] thread play_loop_on_machine(); + } + level notify( "specialty_finalstand_power_on" ); + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "whoswho" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "whoswho" ].power_on_callback ); + } + level waittill( "chugabud_off" ); + if ( isDefined( level.machine_assets[ "whoswho" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "whoswho" ].power_off_callback ); + } + array_thread( machine, ::turn_perk_off ); + players = get_players(); + foreach ( player in players ) + { + player.hasperkspecialtychugabud = undefined; + } + } +} + +set_power_on( state ) //checked matches cerberus output +{ + self.power_on = state; +} + +turn_perk_off( ishidden ) //checked matches cerberus output +{ + self notify( "stop_loopsound" ); + newmachine = spawn( "script_model", self.origin ); + newmachine.angles = self.angles; + newmachine.targetname = self.targetname; + if ( is_true( ishidden ) ) + { + newmachine.ishidden = 1; + newmachine hide(); + } + self delete(); +} + +play_loop_on_machine() //checked matches cerberus output +{ + if ( isDefined( level.sndperksacolaloopoverride ) ) + { + return; + } + sound_ent = spawn( "script_origin", self.origin ); + sound_ent playloopsound( "zmb_perks_machine_loop" ); + sound_ent linkto( self ); + self waittill( "stop_loopsound" ); + sound_ent unlink(); + sound_ent delete(); +} + +perk_fx( fx, turnofffx ) //checked matches cerberus output +{ + if ( isDefined( turnofffx ) ) + { + self.perk_fx = 0; + } + else + { + wait 3; + if ( isDefined( self ) && !is_true( self.perk_fx ) ) + { + playfxontag( level._effect[ fx ], self, "tag_origin" ); + self.perk_fx = 1; + } + } +} + +electric_perks_dialog() //checked partially changed to match cerberus output +{ + self endon( "death" ); + wait 0.01; + flag_wait( "start_zombie_round_logic" ); + players = get_players(); + if ( players.size == 1 ) + { + return; + } + self endon( "warning_dialog" ); + level endon( "switch_flipped" ); + timer = 0; + while ( 1 ) + { + wait 0.5; + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( !isDefined( players[ i ] ) ) + { + i++; + continue; + } + else + { + dist = distancesquared( players[ i ].origin, self.origin ); + } + if ( dist > 4900 ) + { + timer = 0; + i++; + continue; + } + else if ( dist < 4900 && timer < 3 ) + { + wait 0.5; + timer++; + } + if ( dist < 4900 && timer == 3 ) + { + if ( !isDefined( players[ i ] ) ) + { + i++; + continue; + } + players[ i ] thread do_player_vo( "vox_start", 5 ); + wait 3; + self notify( "warning_dialog" ); + /* +/# + iprintlnbold( "warning_given" ); +#/ + */ + } + i++; + } + } +} + +reset_vending_hint_string() //checked matches cerberus output +{ + perk = self.script_noteworthy; + solo = maps/mp/zombies/_zm_perks::use_solo_revive(); + switch( perk ) + { + case "specialty_armorvest": + case "specialty_armorvest_upgrade": + self sethintstring( &"ZOMBIE_PERK_JUGGERNAUT", self.cost ); + break; + case "specialty_quickrevive": + case "specialty_quickrevive_upgrade": + if ( solo ) + { + self sethintstring( &"ZOMBIE_PERK_QUICKREVIVE_SOLO", self.cost ); + } + else + { + self sethintstring( &"ZOMBIE_PERK_QUICKREVIVE", self.cost ); + } + break; + case "specialty_fastreload": + case "specialty_fastreload_upgrade": + self sethintstring( &"ZOMBIE_PERK_FASTRELOAD", self.cost ); + break; + case "specialty_rof": + case "specialty_rof_upgrade": + self sethintstring( &"ZOMBIE_PERK_DOUBLETAP", self.cost ); + break; + case "specialty_longersprint": + case "specialty_longersprint_upgrade": + self sethintstring( &"ZOMBIE_PERK_MARATHON", self.cost ); + break; + case "specialty_deadshot": + case "specialty_deadshot_upgrade": + self sethintstring( &"ZOMBIE_PERK_DEADSHOT", self.cost ); + break; + case "specialty_additionalprimaryweapon": + case "specialty_additionalprimaryweapon_upgrade": + self sethintstring( &"ZOMBIE_PERK_ADDITIONALPRIMARYWEAPON", self.cost ); + break; + case "specialty_scavenger": + case "specialty_scavenger_upgrade": + self sethintstring( &"ZOMBIE_PERK_TOMBSTONE", self.cost ); + break; + case "specialty_finalstand": + case "specialty_finalstand_upgrade": + self sethintstring( &"ZOMBIE_PERK_CHUGABUD", self.cost ); + break; + default: + self sethintstring( ( perk + " Cost: " ) + level.zombie_vars[ "zombie_perk_cost" ] ); + } + if ( isDefined( level._custom_perks ) ) + { + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].cost ) && isDefined( level._custom_perks[ perk ].hint_string ) ) + { + self sethintstring( level._custom_perks[ perk ].hint_string, level._custom_perks[ perk ].cost ); + } + } +} + +vending_trigger_think() //checked changed to match cerberus output +{ + self endon( "death" ); + wait 0.01; + perk = self.script_noteworthy; + solo = 0; + start_on = 0; + level.revive_machine_is_solo = 0; + + if ( isdefined( perk ) && perk == "specialty_quickrevive" || perk == "specialty_quickrevive_upgrade" ) + { + flag_wait("start_zombie_round_logic"); + solo = use_solo_revive(); + self endon("stop_quickrevive_logic"); + level.quick_revive_trigger = self; + if( solo ) + { + if ( !is_true( level.revive_machine_is_solo ) ) + { + start_on = 1; + players = get_players(); + foreach ( player in players ) + { + if ( !isdefined( player.lives ) ) + { + player.lives = 0; + } + } + level maps/mp/zombies/_zm::set_default_laststand_pistol( 1 ); + } + level.revive_machine_is_solo = 1; + } + } + self sethintstring( &"ZOMBIE_NEED_POWER" ); + self setcursorhint( "HINT_NOICON" ); + self usetriggerrequirelookat(); + cost = level.zombie_vars[ "zombie_perk_cost" ]; + switch( perk ) + { + case "specialty_armorvest": + case "specialty_armorvest_upgrade": + cost = 2500; + break; + case "specialty_quickrevive": + case "specialty_quickrevive_upgrade": + if ( solo ) + { + cost = 500; + } + else + { + cost = 1500; + } + break; + case "specialty_fastreload": + case "specialty_fastreload_upgrade": + cost = 3000; + break; + case "specialty_rof": + case "specialty_rof_upgrade": + cost = 2000; + break; + case "specialty_longersprint": + case "specialty_longersprint_upgrade": + cost = 2000; + break; + case "specialty_deadshot": + case "specialty_deadshot_upgrade": + cost = 1500; + break; + case "specialty_additionalprimaryweapon": + case "specialty_additionalprimaryweapon_upgrade": + cost = 4000; + break; + } + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].cost ) ) + { + cost = level._custom_perks[ perk ].cost; + } + self.cost = cost; + if ( !start_on ) + { + notify_name = perk + "_power_on"; + level waittill( notify_name ); + } + start_on = 0; + if ( !isDefined( level._perkmachinenetworkchoke ) ) + { + level._perkmachinenetworkchoke = 0; + } + else + { + level._perkmachinenetworkchoke++; + } + for ( i = 0; i < level._perkmachinenetworkchoke; i++ ) + { + wait_network_frame(); + } + self thread maps/mp/zombies/_zm_audio::perks_a_cola_jingle_timer(); + self thread check_player_has_perk( perk ); + switch( perk ) + { + case "specialty_armorvest": + case "specialty_armorvest_upgrade": + self sethintstring( &"ZOMBIE_PERK_JUGGERNAUT", cost ); + break; + case "specialty_quickrevive": + case "specialty_quickrevive_upgrade": + if ( solo ) + { + self sethintstring( &"ZOMBIE_PERK_QUICKREVIVE_SOLO", cost ); + } + else + { + self sethintstring( &"ZOMBIE_PERK_QUICKREVIVE", cost ); + } + break; + case "specialty_fastreload": + case "specialty_fastreload_upgrade": + self sethintstring( &"ZOMBIE_PERK_FASTRELOAD", cost ); + break; + case "specialty_rof": + case "specialty_rof_upgrade": + self sethintstring( &"ZOMBIE_PERK_DOUBLETAP", cost ); + break; + case "specialty_longersprint": + case "specialty_longersprint_upgrade": + self sethintstring( &"ZOMBIE_PERK_MARATHON", cost ); + break; + case "specialty_deadshot": + case "specialty_deadshot_upgrade": + self sethintstring( &"ZOMBIE_PERK_DEADSHOT", cost ); + break; + case "specialty_additionalprimaryweapon": + case "specialty_additionalprimaryweapon_upgrade": + self sethintstring( &"ZOMBIE_PERK_ADDITIONALPRIMARYWEAPON", cost ); + break; + case "specialty_scavenger": + case "specialty_scavenger_upgrade": + self sethintstring( &"ZOMBIE_PERK_TOMBSTONE", cost ); + break; + case "specialty_finalstand": + case "specialty_finalstand_upgrade": + self sethintstring( &"ZOMBIE_PERK_CHUGABUD", cost ); + break; + default: + self sethintstring( ( perk + " Cost: " ) + level.zombie_vars[ "zombie_perk_cost" ] ); + } + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].hint_string ) ) + { + self sethintstring( level._custom_perks[ perk ].hint_string, cost ); + } + for ( ;; ) + { + self waittill( "trigger", player ); + index = maps/mp/zombies/_zm_weapons::get_player_index( player ); + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() || is_true( player.intermission ) ) + { + wait 0.1; + continue; + } + if ( player in_revive_trigger() ) + { + wait 0.1; + continue; + } + if ( !player maps/mp/zombies/_zm_magicbox::can_buy_weapon() ) + { + wait 0.1; + continue; + } + if ( player isthrowinggrenade() ) + { + wait 0.1; + continue; + } + if ( player isswitchingweapons() ) + { + wait 0.1; + continue; + } + if ( player.is_drinking > 0 ) + { + wait 0.1; + continue; + } + if ( player hasperk( perk ) || player has_perk_paused( perk ) ) + { + cheat = 0; + /* +/# + if ( getDvarInt( "zombie_cheat" ) >= 5 ) + { + cheat = 1; +#/ + } + */ + if ( cheat != 1 ) + { + self playsound( "deny" ); + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "perk_deny", undefined, 1 ); + continue; + } + } + if ( isDefined( level.custom_perk_validation ) ) + { + valid = self [[ level.custom_perk_validation ]]( player ); + if ( !valid ) + { + continue; + } + } + current_cost = cost; + if ( player maps/mp/zombies/_zm_pers_upgrades_functions::is_pers_double_points_active() ) + { + current_cost = player maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_double_points_cost( current_cost ); + } + if ( player.score < current_cost ) + { + self playsound( "evt_perk_deny" ); + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "perk_deny", undefined, 0 ); + continue; + } + + if ( player.num_perks >= player get_player_perk_purchase_limit() ) + { + self playsound( "evt_perk_deny" ); + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "sigh" ); + continue; + } + sound = "evt_bottle_dispense"; + playsoundatposition( sound, self.origin ); + player maps/mp/zombies/_zm_score::minus_to_player_score( current_cost, 1 ); + player.perk_purchased = perk; + self thread maps/mp/zombies/_zm_audio::play_jingle_or_stinger( self.script_label ); + self thread vending_trigger_post_think( player, perk ); + } +} + +vending_trigger_post_think( player, perk ) //checked matches cerberus output +{ + player endon( "disconnect" ); + player endon( "end_game" ); + player endon( "perk_abort_drinking" ); + gun = player perk_give_bottle_begin( perk ); + evt = player waittill_any_return( "fake_death", "death", "player_downed", "weapon_change_complete" ); + if ( evt == "weapon_change_complete" ) + { + player thread wait_give_perk( perk, 1 ); + } + player perk_give_bottle_end( gun, perk ); + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() || isDefined( player.intermission ) && player.intermission ) + { + return; + } + player notify( "burp" ); + if ( is_true( level.pers_upgrade_cash_back ) ) + { + player maps/mp/zombies/_zm_pers_upgrades_functions::cash_back_player_drinks_perk(); + } + if ( is_true( level.pers_upgrade_perk_lose ) ) + { + player thread maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_perk_lose_bought(); + } + if ( isDefined( level.perk_bought_func ) ) + { + player [[ level.perk_bought_func ]]( perk ); + } + player.perk_purchased = undefined; + if ( is_false( self.power_on ) ) + { + wait 1; + perk_pause( self.script_noteworthy ); + } + bbprint( "zombie_uses", "playername %s playerscore %d round %d name %s x %f y %f z %f type %s", player.name, player.score, level.round_number, perk, self.origin, "perk" ); +} + +solo_revive_buy_trigger_move( revive_trigger_noteworthy ) //checked changed to match cerberus output +{ + self endon( "death" ); + revive_perk_triggers = getentarray( revive_trigger_noteworthy, "script_noteworthy" ); + foreach ( revive_perk_trigger in revive_perk_triggers ) + { + self thread solo_revive_buy_trigger_move_trigger( revive_perk_trigger ); + } +} + +solo_revive_buy_trigger_move_trigger( revive_perk_trigger ) //checked matches cerberus output +{ + self endon( "death" ); + revive_perk_trigger setinvisibletoplayer( self ); + if ( level.solo_lives_given >= 3 ) + { + revive_perk_trigger trigger_off(); + if ( isDefined( level._solo_revive_machine_expire_func ) ) + { + revive_perk_trigger [[ level._solo_revive_machine_expire_func ]](); + } + return; + } + while ( self.lives > 0 ) + { + wait 0.1; + } + revive_perk_trigger setvisibletoplayer( self ); +} + +wait_give_perk( perk, bought ) //checked matches cerberus output +{ + self endon( "player_downed" ); + self endon( "disconnect" ); + self endon( "end_game" ); + self endon( "perk_abort_drinking" ); + self waittill_notify_or_timeout( "burp", 0.5 ); + self give_perk( perk, bought ); +} + +return_retained_perks() //checked changed to match cerberus output +{ + if ( isDefined( self._retain_perks_array ) ) + { + keys = getarraykeys( self._retain_perks_array ); + foreach ( perk in keys ) + { + if ( is_true( self._retain_perks_array[ perk ] ) ) + { + self give_perk( perk, 0 ); + } + } + } +} + +give_perk( perk, bought ) //checked changed to match cerberus output +{ + self setperk( perk ); + self.num_perks++; + if ( is_true( bought ) ) + { + self maps/mp/zombies/_zm_audio::playerexert( "burp" ); + if ( is_true( level.remove_perk_vo_delay ) ) + { + self maps/mp/zombies/_zm_audio::perk_vox( perk ); + } + else + { + self delay_thread( 1.5, ::perk_vox, perk ); + } + self setblur( 4, 0.1 ); + wait 0.1; + self setblur( 0, 0.1 ); + self notify( "perk_bought", perk ); + } + self perk_set_max_health_if_jugg( perk, 1, 0 ); + if ( !is_true( level.disable_deadshot_clientfield ) ) + { + if ( perk == "specialty_deadshot" ) + { + self setclientfieldtoplayer( "deadshot_perk", 1 ); + } + else if ( perk == "specialty_deadshot_upgrade" ) + { + self setclientfieldtoplayer( "deadshot_perk", 1 ); + } + } + if ( perk == "specialty_scavenger" ) + { + self.hasperkspecialtytombstone = 1; + } + players = get_players(); + if ( use_solo_revive() && perk == "specialty_quickrevive" ) + { + self.lives = 1; + if ( !isDefined( level.solo_lives_given ) ) + { + level.solo_lives_given = 0; + } + if ( isDefined( level.solo_game_free_player_quickrevive ) ) + { + level.solo_game_free_player_quickrevive = undefined; + } + else + { + level.solo_lives_given++; + } + if ( level.solo_lives_given >= 3 ) + { + flag_set( "solo_revive" ); + } + self thread solo_revive_buy_trigger_move( perk ); + } + if ( perk == "specialty_finalstand" ) + { + self.lives = 1; + self.hasperkspecialtychugabud = 1; + self notify( "perk_chugabud_activated" ); + } + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].player_thread_give ) ) + { + self thread [[ level._custom_perks[ perk ].player_thread_give ]](); + } + self set_perk_clientfield( perk, 1 ); + maps/mp/_demo::bookmark( "zm_player_perk", getTime(), self ); + self maps/mp/zombies/_zm_stats::increment_client_stat( "perks_drank" ); + self maps/mp/zombies/_zm_stats::increment_client_stat( perk + "_drank" ); + self maps/mp/zombies/_zm_stats::increment_player_stat( perk + "_drank" ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "perks_drank" ); + if ( !isDefined( self.perk_history ) ) + { + self.perk_history = []; + } + self.perk_history = add_to_array( self.perk_history, perk, 0 ); + if ( !isDefined( self.perks_active ) ) + { + self.perks_active = []; + } + self.perks_active[ self.perks_active.size ] = perk; + self notify( "perk_acquired" ); + self thread perk_think( perk ); +} + +perk_set_max_health_if_jugg( perk, set_premaxhealth, clamp_health_to_max_health ) //checked matches cerberus output +{ + max_total_health = undefined; + if ( perk == "specialty_armorvest" ) + { + if ( set_premaxhealth ) + { + self.premaxhealth = self.maxhealth; + } + max_total_health = level.zombie_vars[ "zombie_perk_juggernaut_health" ]; + } + else if ( perk == "specialty_armorvest_upgrade" ) + { + if ( set_premaxhealth ) + { + self.premaxhealth = self.maxhealth; + } + max_total_health = level.zombie_vars[ "zombie_perk_juggernaut_health_upgrade" ]; + } + else if ( perk == "jugg_upgrade" ) + { + if ( set_premaxhealth ) + { + self.premaxhealth = self.maxhealth; + } + if ( self hasperk( "specialty_armorvest" ) ) + { + max_total_health = level.zombie_vars[ "zombie_perk_juggernaut_health" ]; + } + else + { + max_total_health = 100; + } + } + else + { + if ( perk == "health_reboot" ) + { + max_total_health = 100; + } + } + if ( isDefined( max_total_health ) ) + { + if ( self maps/mp/zombies/_zm_pers_upgrades_functions::pers_jugg_active() ) + { + max_total_health += level.pers_jugg_upgrade_health_bonus; + } + self setmaxhealth( max_total_health ); + if ( isDefined( clamp_health_to_max_health ) && clamp_health_to_max_health == 1 ) + { + if ( self.health > self.maxhealth ) + { + self.health = self.maxhealth; + } + } + } +} + +check_player_has_perk( perk ) //checked partially changed to match cerberus output +{ + self endon( "death" ); + /* +/# + if ( getDvarInt( "zombie_cheat" ) >= 5 ) + { + return; +#/ + } + */ + dist = 16384; + while ( 1 ) + { + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( distancesquared( players[ i ].origin, self.origin ) < dist ) + { + if ( !players[ i ] hasperk( perk ) && !players[ i ] has_perk_paused( perk ) && !players[ i ] in_revive_trigger() && !is_equipment_that_blocks_purchase( players[ i ] getcurrentweapon() ) && !players[ i ] hacker_active() ) + { + self setinvisibletoplayer( players[ i ], 0 ); + i++; + continue; + } + self setinvisibletoplayer( players[ i ], 1 ); + } + i++; + } + wait 0.1; + } +} + +vending_set_hintstring( perk ) //checked matches cerberus output +{ + switch( perk ) + { + case "specialty_armorvest": + case "specialty_armorvest_upgrade": + break; + } +} + +perk_think( perk ) //checked changed to match cerberus output +{ +/* +/# + if ( getDvarInt( "zombie_cheat" ) >= 5 ) + { + if ( isDefined( self.perk_hud[ perk ] ) ) + { + return; +#/ + } + } +*/ + perk_str = perk + "_stop"; + result = self waittill_any_return( "fake_death", "death", "player_downed", perk_str ); + do_retain = 1; + if ( use_solo_revive() && perk == "specialty_quickrevive" ) + { + do_retain = 0; + } + if ( do_retain ) + { + if ( is_true( self._retain_perks ) ) + { + return; + } + else if ( isDefined( self._retain_perks_array ) && is_true( self._retain_perks_array[ perk ] ) ) + { + return; + } + } + self unsetperk( perk ); + self.num_perks--; + + switch( perk ) + { + case "specialty_armorvest": + self setmaxhealth( 100 ); + break; + case "specialty_additionalprimaryweapon": + if ( result == perk_str ) + { + self maps/mp/zombies/_zm::take_additionalprimaryweapon(); + } + break; + case "specialty_deadshot": + if ( !is_true( level.disable_deadshot_clientfield ) ) + { + self setclientfieldtoplayer( "deadshot_perk", 0 ); + } + break; + case "specialty_deadshot_upgrade": + if ( !is_true( level.disable_deadshot_clientfield ) ) + { + self setclientfieldtoplayer( "deadshot_perk", 0 ); + } + break; + } + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].player_thread_take ) ) + { + self thread [[ level._custom_perks[ perk ].player_thread_take ]](); + } + self set_perk_clientfield( perk, 0 ); + self.perk_purchased = undefined; + if ( isDefined( level.perk_lost_func ) ) + { + self [[ level.perk_lost_func ]]( perk ); + } + if ( isDefined( self.perks_active ) && isinarray( self.perks_active, perk ) ) + { + arrayremovevalue( self.perks_active, perk, 0 ); + } + self notify( "perk_lost" ); +} + +set_perk_clientfield( perk, state ) //checked matches cerberus output +{ + switch( perk ) + { + case "specialty_additionalprimaryweapon": + self setclientfieldtoplayer( "perk_additional_primary_weapon", state ); + break; + case "specialty_deadshot": + self setclientfieldtoplayer( "perk_dead_shot", state ); + break; + case "specialty_flakjacket": + self setclientfieldtoplayer( "perk_dive_to_nuke", state ); + break; + case "specialty_rof": + self setclientfieldtoplayer( "perk_double_tap", state ); + break; + case "specialty_armorvest": + self setclientfieldtoplayer( "perk_juggernaut", state ); + break; + case "specialty_longersprint": + self setclientfieldtoplayer( "perk_marathon", state ); + break; + case "specialty_quickrevive": + self setclientfieldtoplayer( "perk_quick_revive", state ); + break; + case "specialty_fastreload": + self setclientfieldtoplayer( "perk_sleight_of_hand", state ); + break; + case "specialty_scavenger": + self setclientfieldtoplayer( "perk_tombstone", state ); + break; + case "specialty_finalstand": + self setclientfieldtoplayer( "perk_chugabud", state ); + break; + default: + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].clientfield_set ) ) + { + self [[ level._custom_perks[ perk ].clientfield_set ]]( state ); + } + } +} + +perk_hud_destroy( perk ) //checked changed to match cerberus output +{ + self.perk_hud[ perk ] destroy_hud(); + self.perk_hud[ perk ] = undefined; +} + +perk_hud_grey( perk, grey_on_off ) //checked matches cerberus output +{ + if ( grey_on_off ) + { + self.perk_hud[ perk ].alpha = 0.3; + } + else + { + self.perk_hud[ perk ].alpha = 1; + } +} + +perk_hud_flash() //checked matches cerberus output +{ + self endon( "death" ); + self.flash = 1; + self scaleovertime( 0.05, 32, 32 ); + wait 0.3; + self scaleovertime( 0.05, 24, 24 ); + wait 0.3; + self.flash = 0; +} + +perk_flash_audio( perk ) //checked matches cerberus output +{ + alias = undefined; + switch( perk ) + { + case "specialty_armorvest": + alias = "zmb_hud_flash_jugga"; + break; + case "specialty_quickrevive": + alias = "zmb_hud_flash_revive"; + break; + case "specialty_fastreload": + alias = "zmb_hud_flash_speed"; + break; + case "specialty_longersprint": + alias = "zmb_hud_flash_stamina"; + break; + case "specialty_flakjacket": + alias = "zmb_hud_flash_phd"; + break; + case "specialty_deadshot": + alias = "zmb_hud_flash_deadshot"; + break; + case "specialty_additionalprimaryweapon": + alias = "zmb_hud_flash_additionalprimaryweapon"; + break; + } + if ( isDefined( alias ) ) + { + self playlocalsound( alias ); + } +} + +perk_hud_start_flash( perk ) //checked does not match cerberus output did not change +{ + if ( self hasperk( perk ) && isDefined( self.perk_hud ) ) + { + hud = self.perk_hud[ perk ]; + if ( isDefined( hud ) ) + { + if ( !is_true( hud.flash ) ) + { + hud thread perk_hud_flash(); + self thread perk_flash_audio( perk ); + } + } + } +} + +perk_hud_stop_flash( perk, taken ) //checked matches cerberus output +{ + if ( self hasperk( perk ) && isDefined( self.perk_hud ) ) + { + hud = self.perk_hud[ perk ]; + if ( isDefined( hud ) ) + { + hud.flash = undefined; + if ( isDefined( taken ) ) + { + hud notify( "stop_flash_perk" ); + } + } + } +} + +perk_give_bottle_begin( perk ) //checked matches cerberus output +{ + self increment_is_drinking(); + self disable_player_move_states( 1 ); + gun = self getcurrentweapon(); + weapon = ""; + switch( perk ) + { + case " _upgrade": + case "specialty_armorvest": + weapon = level.machine_assets[ "juggernog" ].weapon; + break; + case "specialty_quickrevive": + case "specialty_quickrevive_upgrade": + weapon = level.machine_assets[ "revive" ].weapon; + break; + case "specialty_fastreload": + case "specialty_fastreload_upgrade": + weapon = level.machine_assets[ "speedcola" ].weapon; + break; + case "specialty_rof": + case "specialty_rof_upgrade": + weapon = level.machine_assets[ "doubletap" ].weapon; + break; + case "specialty_longersprint": + case "specialty_longersprint_upgrade": + weapon = level.machine_assets[ "marathon" ].weapon; + break; + case "specialty_flakjacket": + case "specialty_flakjacket_upgrade": + weapon = level.machine_assets[ "divetonuke" ].weapon; + break; + case "specialty_deadshot": + case "specialty_deadshot_upgrade": + weapon = level.machine_assets[ "deadshot" ].weapon; + break; + case "specialty_additionalprimaryweapon": + case "specialty_additionalprimaryweapon_upgrade": + weapon = level.machine_assets[ "additionalprimaryweapon" ].weapon; + break; + case "specialty_scavenger": + case "specialty_scavenger_upgrade": + weapon = level.machine_assets[ "tombstone" ].weapon; + break; + case "specialty_finalstand": + case "specialty_finalstand_upgrade": + weapon = level.machine_assets[ "whoswho" ].weapon; + break; + } + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].perk_bottle ) ) + { + weapon = level._custom_perks[ perk ].perk_bottle; + } + self giveweapon( weapon ); + self switchtoweapon( weapon ); + return gun; +} + +perk_give_bottle_end( gun, perk ) //checked matches cerberus output +{ + self endon( "perk_abort_drinking" ); + /* +/# + assert( !is_zombie_perk_bottle( gun ) ); +#/ +/# + assert( gun != level.revive_tool ); +#/ + */ + self enable_player_move_states(); + weapon = ""; + switch( perk ) + { + case "specialty_rof": + case "specialty_rof_upgrade": + weapon = level.machine_assets[ "doubletap" ].weapon; + break; + case "specialty_longersprint": + case "specialty_longersprint_upgrade": + weapon = level.machine_assets[ "marathon" ].weapon; + break; + case "specialty_flakjacket": + case "specialty_flakjacket_upgrade": + weapon = level.machine_assets[ "divetonuke" ].weapon; + break; + case "specialty_armorvest": + case "specialty_armorvest_upgrade": + weapon = level.machine_assets[ "juggernog" ].weapon; + self.jugg_used = 1; + break; + case "specialty_quickrevive": + case "specialty_quickrevive_upgrade": + weapon = level.machine_assets[ "revive" ].weapon; + break; + case "specialty_fastreload": + case "specialty_fastreload_upgrade": + weapon = level.machine_assets[ "speedcola" ].weapon; + self.speed_used = 1; + break; + case "specialty_deadshot": + case "specialty_deadshot_upgrade": + weapon = level.machine_assets[ "deadshot" ].weapon; + break; + case "specialty_additionalprimaryweapon": + case "specialty_additionalprimaryweapon_upgrade": + weapon = level.machine_assets[ "additionalprimaryweapon" ].weapon; + break; + case "specialty_scavenger": + case "specialty_scavenger_upgrade": + weapon = level.machine_assets[ "tombstone" ].weapon; + break; + case "specialty_finalstand": + case "specialty_finalstand_upgrade": + weapon = level.machine_assets[ "whoswho" ].weapon; + break; + } + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].perk_bottle ) ) + { + weapon = level._custom_perks[ perk ].perk_bottle; + } + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || is_true( self.intermission ) ) + { + self takeweapon( weapon ); + return; + } + self takeweapon( weapon ); + if ( self is_multiple_drinking() ) + { + self decrement_is_drinking(); + return; + } + else if ( gun != "none" && !is_placeable_mine( gun ) && !is_equipment_that_blocks_purchase( gun ) ) + { + self switchtoweapon( gun ); + if ( is_melee_weapon( gun ) ) + { + self decrement_is_drinking(); + return; + } + } + else + { + primaryweapons = self getweaponslistprimaries(); + if ( isDefined( primaryweapons ) && primaryweapons.size > 0 ) + { + self switchtoweapon( primaryweapons[ 0 ] ); + } + } + self waittill( "weapon_change_complete" ); + self decrement_is_drinking(); + if ( !self maps/mp/zombies/_zm_laststand::player_is_in_laststand() && !is_true( self.intermission ) ) + { + self decrement_is_drinking(); + } + +} + +perk_abort_drinking( post_delay ) //checked matches cerberus output +{ + if ( self.is_drinking ) + { + self notify( "perk_abort_drinking" ); + self decrement_is_drinking(); + self enable_player_move_states(); + if ( isDefined( post_delay ) ) + { + wait post_delay; + } + } +} + +give_random_perk() //checked partially changed to match cerberus output +{ + random_perk = undefined; + vending_triggers = getentarray( "zombie_vending", "targetname" ); + perks = []; + i = 0; + while ( i < vending_triggers.size ) + { + perk = vending_triggers[ i ].script_noteworthy; + if ( isDefined( self.perk_purchased ) && self.perk_purchased == perk ) + { + i++; + continue; + } + if ( perk == "specialty_weapupgrade" ) + { + i++; + continue; + } + if ( !self hasperk( perk ) && !self has_perk_paused( perk ) ) + { + perks[ perks.size ] = perk; + } + i++; + } + if ( perks.size > 0 ) + { + perks = array_randomize( perks ); + random_perk = perks[ 0 ]; + self give_perk( random_perk ); + } + else + { + self playsoundtoplayer( level.zmb_laugh_alias, self ); + } + return random_perk; +} + +lose_random_perk() //checked partially changed to match cerberus output +{ + vending_triggers = getentarray( "zombie_vending", "targetname" ); + perks = []; + i = 0; + while ( i < vending_triggers.size ) + { + perk = vending_triggers[ i ].script_noteworthy; + if ( isDefined( self.perk_purchased ) && self.perk_purchased == perk ) + { + i++; + continue; + } + if ( self hasperk( perk ) || self has_perk_paused( perk ) ) + { + perks[ perks.size ] = perk; + } + i++; + } + if ( perks.size > 0 ) + { + perks = array_randomize( perks ); + perk = perks[ 0 ]; + perk_str = perk + "_stop"; + self notify( perk_str ); + if ( use_solo_revive() && perk == "specialty_quickrevive" ) + { + self.lives--; + + } + } +} + +update_perk_hud() +{ + if ( isDefined( self.perk_hud ) ) + { + keys = getarraykeys( self.perk_hud ); + for ( i = 0; i < self.perk_hud.size; i++) + { + self.perk_hud[ keys[ i ] ].x = i * 30; + } + } +} + +quantum_bomb_give_nearest_perk_validation( position ) //checked changed to match cerberus output +{ + vending_triggers = getentarray( "zombie_vending", "targetname" ); + range_squared = 32400; + for ( i = 0; i < vending_triggers.size; i++ ) + { + if ( distancesquared( vending_triggers[ i ].origin, position ) < range_squared ) + { + return 1; + } + } + return 0; +} + +quantum_bomb_give_nearest_perk_result( position ) //checked partially changed to match cerberus output +{ + [[ level.quantum_bomb_play_mystery_effect_func ]]( position ); + vending_triggers = getentarray( "zombie_vending", "targetname" ); + nearest = 0; + for ( i = 1; i < vending_triggers.size; i++ ) + { + if ( distancesquared( vending_triggers[ i ].origin, position ) < distancesquared( vending_triggers[ nearest ].origin, position ) ) + { + nearest = i; + } + } + players = get_players(); + perk = vending_triggers[ nearest ].script_noteworthy; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( player.sessionstate == "spectator" || player maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + i++; + continue; + } + if ( !player hasperk( perk ) && isDefined( player.perk_purchased ) && player.perk_purchased != perk && randomint( 5 ) ) + { + if ( player == self ) + { + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "kill", "quant_good" ); + } + player give_perk( perk ); + player [[ level.quantum_bomb_play_player_effect_func ]](); + } + i++; + } +} + +perk_pause( perk ) //checked changed to match cerberus output +{ + if ( perk == "Pack_A_Punch" || perk == "specialty_weapupgrade" ) + { + return; + } + for ( j = 0; j < get_players().size; j++ ) + { + player = get_players()[ j ]; + if ( !isDefined( player.disabled_perks ) ) + { + player.disabled_perks = []; + } + if ( !is_true( player.disabled_perks[ perk ] ) ) + { + player.disabled_perks[ perk ] = player hasperk( perk ); + } + if ( player.disabled_perks[ perk ] ) + { + player unsetperk( perk ); + player set_perk_clientfield( perk, 2 ); + if ( perk == "specialty_armorvest" || perk == "specialty_armorvest_upgrade" ) + { + player setmaxhealth( player.premaxhealth ); + if ( player.health > player.maxhealth ) + { + player.health = player.maxhealth; + } + } + if ( perk == "specialty_additionalprimaryweapon" || perk == "specialty_additionalprimaryweapon_upgrade" ) + { + player maps/mp/zombies/_zm::take_additionalprimaryweapon(); + } + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].player_thread_take ) ) + { + player thread [[ level._custom_perks[ perk ].player_thread_take ]](); + } + /* +/# + println( " ZM PERKS " + player.name + " paused perk " + perk + "\n" ); +#/ + */ + } + } +} + +perk_unpause( perk ) //checked changed to match cerberus output +{ + if ( !isDefined( perk ) ) + { + return; + } + if ( perk == "Pack_A_Punch" ) + { + return; + } + for ( j = 0; j < get_players().size; j++ ) + { + player = get_players()[ j ]; + if ( isDefined( player.disabled_perks ) && is_true( player.disabled_perks[ perk ] ) ) + { + player.disabled_perks[ perk ] = 0; + player set_perk_clientfield( perk, 1 ); + player setperk( perk ); + /* +/# + println( " ZM PERKS " + player.name + " unpaused perk " + perk + "\n" ); +#/ + */ + if ( issubstr( perk, "specialty_scavenger" ) ) + { + player.hasperkspecialtytombstone = 1; + } + player perk_set_max_health_if_jugg( perk, 0, 0 ); + if ( isDefined( level._custom_perks[ perk ] ) && isDefined( level._custom_perks[ perk ].player_thread_give ) ) + { + player thread [[ level._custom_perks[ perk ].player_thread_give ]](); + } + } + } +} + +perk_pause_all_perks() //checked changed to match cerberus output +{ + vending_triggers = getentarray( "zombie_vending", "targetname" ); + foreach ( trigger in vending_triggers ) + { + maps/mp/zombies/_zm_perks::perk_pause( trigger.script_noteworthy ); + } +} + +perk_unpause_all_perks() //checked changed to match cerberus output +{ + vending_triggers = getentarray( "zombie_vending", "targetname" ); + foreach ( trigger in vending_triggers ) + { + maps/mp/zombies/_zm_perks::perk_unpause( trigger.script_noteworthy ); + } +} + +has_perk_paused( perk ) //checked matches cerberus output +{ + if ( isDefined( self.disabled_perks ) && is_true( self.disabled_perks[ perk ] ) ) + { + return 1; + } + return 0; +} + +getvendingmachinenotify() //checked matches cerberus output +{ + if ( !isDefined( self ) ) + { + return ""; + } + switch( self.script_noteworthy ) + { + case "specialty_armorvest": + case "specialty_armorvest_upgrade": + return "juggernog"; + case "specialty_quickrevive": + case "specialty_quickrevive_upgrade": + return "revive"; + case "specialty_fastreload": + case "specialty_fastreload_upgrade": + return "sleight"; + case "specialty_rof": + case "specialty_rof_upgrade": + return "doubletap"; + case "specialty_longersprint": + case "specialty_longersprint_upgrade": + return "marathon"; + case "specialty_flakjacket": + case "specialty_flakjacket_upgrade": + return "divetonuke"; + case "specialty_deadshot": + case "specialty_deadshot_upgrade": + return "deadshot"; + case "specialty_additionalprimaryweapon": + case "specialty_additionalprimaryweapon_upgrade": + return "additionalprimaryweapon"; + case "specialty_scavenger": + case "specialty_scavenger_upgrade": + return "tombstone"; + case "specialty_finalstand": + case "specialty_finalstand_upgrade": + return "chugabud"; + case "specialty_weapupgrade": + return "Pack_A_Punch"; + } + str_perk = undefined; + if ( isDefined( level._custom_perks[ self.script_noteworthy ] ) && isDefined( isDefined( level._custom_perks[ self.script_noteworthy ].alias ) ) ) + { + str_perk = level._custom_perks[ self.script_noteworthy ].alias; + } + return str_perk; +} + +perk_machine_removal( machine, replacement_model ) //checked changed to match cerberus output +{ + if ( !isdefined( machine ) ) + { + return; + } + trig = getent( machine, "script_noteworthy" ); + machine_model = undefined; + if ( isdefined( trig ) ) + { + trig notify( "warning_dialog" ); + if ( isdefined( trig.target ) ) + { + parts = getentarray( trig.target, "targetname" ); + for ( i = 0; i < parts.size; i++ ) + { + if ( isdefined( parts[ i ].classname ) && parts[ i ].classname == "script_model" ) + { + machine_model = parts[ i ]; + } + if ( isdefined( parts[ i ].script_noteworthy ) && parts[ i ].script_noteworthy == "clip" ) + { + model_clip = parts[ i ]; + } + parts[ i ] delete(); + } + } + else if ( isdefined( replacement_model ) && isdefined( machine_model ) ) + { + machine_model setmodel( replacement_model ); + } + else if ( !isdefined( replacement_model ) && isdefined( machine_model ) ) + { + machine_model delete(); + if ( isdefined( model_clip ) ) + { + model_clip delete(); + } + if ( isdefined( trig.clip ) ) + { + trig.clip delete(); + } + } + if ( isdefined( trig.bump ) ) + { + trig.bump delete(); + } + trig delete(); + } +} + +perk_machine_spawn_init() +{ + + 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 + "_perks_" + location; + pos = []; + if ( isdefined( level.override_perk_targetname ) ) + { + structs = getstructarray( level.override_perk_targetname, "targetname" ); + } + else + { + structs = getstructarray( "zm_perk_machine", "targetname" ); + } + if ( match_string == "zclassic_perks_rooftop" || match_string == "zclassic_perks_tomb" || match_string == "zstandard_perks_nuked" ) + { + useDefaultLocation = 1; + } + i = 0; + while ( i < structs.size ) + { + if ( isdefined( structs[ i ].script_string ) ) + { + tokens = strtok( structs[ i ].script_string, " " ); + k = 0; + while ( k < tokens.size ) + { + if ( tokens[ k ] == match_string ) + { + pos[ pos.size ] = structs[ i ]; + } + k++; + } + } + else if ( is_true( useDefaultLocation ) ) + { + pos[ pos.size ] = structs[ i ]; + } + i++; + } + if ( !IsDefined( pos ) || pos.size == 0 ) + { + return; + } + PreCacheModel("zm_collision_perks1"); + for ( i = 0; i < pos.size; i++ ) + { + perk = pos[ i ].script_noteworthy; + if ( IsDefined( perk ) && IsDefined( pos[ i ].model ) ) + { + use_trigger = Spawn( "trigger_radius_use", pos[ i ].origin + ( 0, 0, 30 ), 0, 40, 70 ); + use_trigger.targetname = "zombie_vending"; + use_trigger.script_noteworthy = perk; + use_trigger TriggerIgnoreTeam(); + //use_trigger thread debug_spot(); + + perk_machine = Spawn( "script_model", pos[ i ].origin ); + perk_machine.angles = pos[ i ].angles; + perk_machine SetModel( pos[ i ].model ); + if ( is_true( level._no_vending_machine_bump_trigs ) ) + { + bump_trigger = undefined; + } + else + { + bump_trigger = spawn("trigger_radius", pos[ i ].origin, 0, 35, 64); + bump_trigger.script_activated = 1; + bump_trigger.script_sound = "zmb_perks_bump_bottle"; + bump_trigger.targetname = "audio_bump_trigger"; + if ( perk != "specialty_weapupgrade" ) + { + bump_trigger thread thread_bump_trigger(); + } + } + collision = Spawn( "script_model", pos[ i ].origin, 1 ); + collision.angles = pos[ i ].angles; + collision SetModel( "zm_collision_perks1" ); + collision.script_noteworthy = "clip"; + collision DisconnectPaths(); + + // Connect all of the pieces for easy access. + use_trigger.clip = collision; + use_trigger.machine = perk_machine; + use_trigger.bump = bump_trigger; + //missing code found in cerberus output + if ( isdefined( pos[ i ].blocker_model ) ) + { + use_trigger.blocker_model = pos[ i ].blocker_model; + } + if ( isdefined( pos[ i ].script_int ) ) + { + perk_machine.script_int = pos[ i ].script_int; + } + if ( isdefined( pos[ i ].turn_on_notify ) ) + { + perk_machine.turn_on_notify = pos[ i ].turn_on_notify; + } + switch( perk ) + { + case "specialty_quickrevive": + case "specialty_quickrevive_upgrade": + use_trigger.script_sound = "mus_perks_revive_jingle"; + use_trigger.script_string = "revive_perk"; + use_trigger.script_label = "mus_perks_revive_sting"; + use_trigger.target = "vending_revive"; + perk_machine.script_string = "revive_perk"; + perk_machine.targetname = "vending_revive"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "revive_perk"; + } + break; + case "specialty_fastreload": + case "specialty_fastreload_upgrade": + use_trigger.script_sound = "mus_perks_speed_jingle"; + use_trigger.script_string = "speedcola_perk"; + use_trigger.script_label = "mus_perks_speed_sting"; + use_trigger.target = "vending_sleight"; + perk_machine.script_string = "speedcola_perk"; + perk_machine.targetname = "vending_sleight"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "speedcola_perk"; + } + break; + case "specialty_longersprint": + case "specialty_longersprint_upgrade": + use_trigger.script_sound = "mus_perks_stamin_jingle"; + use_trigger.script_string = "marathon_perk"; + use_trigger.script_label = "mus_perks_stamin_sting"; + use_trigger.target = "vending_marathon"; + perk_machine.script_string = "marathon_perk"; + perk_machine.targetname = "vending_marathon"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "marathon_perk"; + } + break; + case "specialty_armorvest": + case "specialty_armorvest_upgrade": + use_trigger.script_sound = "mus_perks_jugganog_jingle"; + use_trigger.script_string = "jugg_perk"; + use_trigger.script_label = "mus_perks_jugganog_sting"; + use_trigger.longjinglewait = 1; + use_trigger.target = "vending_jugg"; + perk_machine.script_string = "jugg_perk"; + perk_machine.targetname = "vending_jugg"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "jugg_perk"; + } + break; + case "specialty_scavenger": + case "specialty_scavenger_upgrade": + use_trigger.script_sound = "mus_perks_tombstone_jingle"; + use_trigger.script_string = "tombstone_perk"; + use_trigger.script_label = "mus_perks_tombstone_sting"; + use_trigger.target = "vending_tombstone"; + perk_machine.script_string = "tombstone_perk"; + perk_machine.targetname = "vending_tombstone"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "tombstone_perk"; + } + break; + case "specialty_rof": + case "specialty_rof_upgrade": + use_trigger.script_sound = "mus_perks_doubletap_jingle"; + use_trigger.script_string = "tap_perk"; + use_trigger.script_label = "mus_perks_doubletap_sting"; + use_trigger.target = "vending_doubletap"; + perk_machine.script_string = "tap_perk"; + perk_machine.targetname = "vending_doubletap"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "tap_perk"; + } + break; + case "specialty_finalstand": + case "specialty_finalstand_upgrade": + use_trigger.script_sound = "mus_perks_whoswho_jingle"; + use_trigger.script_string = "tap_perk"; + use_trigger.script_label = "mus_perks_whoswho_sting"; + use_trigger.target = "vending_chugabud"; + perk_machine.script_string = "tap_perk"; + perk_machine.targetname = "vending_chugabud"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "tap_perk"; + } + break; + case "specialty_additionalprimaryweapon": + case "specialty_additionalprimaryweapon_upgrade": + use_trigger.script_sound = "mus_perks_mulekick_jingle"; + use_trigger.script_string = "tap_perk"; + use_trigger.script_label = "mus_perks_mulekick_sting"; + use_trigger.target = "vending_additionalprimaryweapon"; + perk_machine.script_string = "tap_perk"; + perk_machine.targetname = "vending_additionalprimaryweapon"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "tap_perk"; + } + break; + case "specialty_weapupgrade": + use_trigger.target = "vending_packapunch"; + use_trigger.script_sound = "mus_perks_packa_jingle"; + use_trigger.script_label = "mus_perks_packa_sting"; + use_trigger.longjinglewait = 1; + perk_machine.targetname = "vending_packapunch"; + flag_pos = getstruct( pos[ i ].target, "targetname" ); + if ( isDefined( flag_pos ) ) + { + perk_machine_flag = spawn( "script_model", flag_pos.origin ); + perk_machine_flag.angles = flag_pos.angles; + perk_machine_flag setmodel( flag_pos.model ); + perk_machine_flag.targetname = "pack_flag"; + perk_machine.target = "pack_flag"; + } + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "perks_rattle"; + } + break; + case "specialty_deadshot": + case "specialty_deadshot_upgrade": + use_trigger.script_sound = "mus_perks_deadshot_jingle"; + use_trigger.script_string = "deadshot_perk"; + use_trigger.script_label = "mus_perks_deadshot_sting"; + use_trigger.target = "vending_deadshot"; + perk_machine.script_string = "deadshot_vending"; + perk_machine.targetname = "vending_deadshot_model"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "deadshot_vending"; + } + break; + default: + if ( isdefined( level._custom_perks[ perk ] ) && isdefined( level._custom_perks[ perk ].perk_machine_set_kvps ) ) + { + [[ level._custom_perks[ perk ].perk_machine_set_kvps ]]( use_trigger, perk_machine, bump_trigger, collision ); + } + break; + } + } + } +} + +get_perk_machine_start_state( perk ) //checked matches cerberus output +{ + if ( is_true( level.vending_machines_powered_on_at_start ) ) + { + return 1; + } + if ( perk == "specialty_quickrevive" || perk == "specialty_quickrevive_upgrade" ) + { + return level.revive_machine_is_solo; + } + return 0; +} + +perks_register_clientfield() //checked matches cerberus output +{ + if ( is_true( level.zombiemode_using_additionalprimaryweapon_perk ) ) + { + registerclientfield( "toplayer", "perk_additional_primary_weapon", 1, 2, "int" ); + } + if ( is_true( level.zombiemode_using_deadshot_perk ) ) + { + registerclientfield( "toplayer", "perk_dead_shot", 1, 2, "int" ); + } + if ( is_true( level.zombiemode_using_doubletap_perk ) ) + { + registerclientfield( "toplayer", "perk_double_tap", 1, 2, "int" ); + } + if ( is_true( level.zombiemode_using_juggernaut_perk ) ) + { + registerclientfield( "toplayer", "perk_juggernaut", 1, 2, "int" ); + } + if ( is_true( level.zombiemode_using_marathon_perk ) ) + { + registerclientfield( "toplayer", "perk_marathon", 1, 2, "int" ); + } + if ( is_true( level.zombiemode_using_revive_perk ) ) + { + registerclientfield( "toplayer", "perk_quick_revive", 1, 2, "int" ); + } + if ( is_true( level.zombiemode_using_sleightofhand_perk ) ) + { + registerclientfield( "toplayer", "perk_sleight_of_hand", 1, 2, "int" ); + } + if ( is_true( level.zombiemode_using_tombstone_perk ) ) + { + registerclientfield( "toplayer", "perk_tombstone", 1, 2, "int" ); + } + if ( is_true( level.zombiemode_using_perk_intro_fx ) ) + { + registerclientfield( "scriptmover", "clientfield_perk_intro_fx", 1000, 1, "int" ); + } + if ( is_true( level.zombiemode_using_chugabud_perk ) ) + { + registerclientfield( "toplayer", "perk_chugabud", 1000, 1, "int" ); + } + if ( isdefined( level._custom_perks ) ) + { + a_keys = getarraykeys(level._custom_perks); + for ( i = 0; i < a_keys.size; i++ ) + { + if ( isdefined( level._custom_perks[ a_keys[ i ] ].clientfield_register ) ) + { + level [[ level._custom_perks[ a_keys[ i ] ].clientfield_register ]](); + } + } + } +} + +thread_bump_trigger() //checked matches cerberus output +{ + for ( ;; ) + { + self waittill( "trigger", trigplayer ); + trigplayer playsound( self.script_sound ); + while ( is_player_valid( trigplayer ) && trigplayer istouching( self ) ) + { + wait 0.5; + } + } +} + +reenable_quickrevive( machine_clip, solo_mode ) //checked changed to match cerberus output +{ + if ( isDefined( level.revive_machine_spawned ) && !is_true( level.revive_machine_spawned ) ) + { + return; + } + wait 0.1; + power_state = 0; + if ( is_true( solo_mode ) ) + { + power_state = 1; + should_pause = 1; + players = get_players(); + foreach ( player in players ) + { + if ( isdefined( player.lives ) && player.lives > 0 && power_state ) + { + should_pause = 0; + } + if ( isdefined( player.lives ) && player.lives < 1 ) + { + should_pause = 1; + } + } + if ( should_pause ) + { + perk_pause( "specialty_quickrevive" ); + } + else + { + perk_unpause( "specialty_quickrevive" ); + } + if ( is_true( level.solo_revive_init ) && flag( "solo_revive" ) ) + { + disable_quickrevive( machine_clip ); + return; + } + update_quickrevive_power_state( 1 ); + unhide_quickrevive(); + restart_quickrevive(); + level notify( "revive_off" ); + wait 0.1; + level notify( "stop_quickrevive_logic" ); + } + else + { + if ( !is_true( level._dont_unhide_quickervive_on_hotjoin ) ) + { + unhide_quickrevive(); + level notify( "revive_off" ); + wait 0.1; + } + level notify( "revive_hide" ); + level notify( "stop_quickrevive_logic" ); + restart_quickrevive(); + if ( flag( "power_on" ) ) + { + power_state = 1; + } + update_quickrevive_power_state( power_state ); + } + level thread turn_revive_on(); + if ( power_state ) + { + perk_unpause( "specialty_quickrevive" ); + level notify( "revive_on" ); + wait 0.1; + level notify( "specialty_quickrevive_power_on" ); + } + else + { + perk_pause( "specialty_quickrevive" ); + } + if ( !is_true( solo_mode ) ) + { + return; + } + should_pause = 1; + players = get_players(); + foreach ( player in players ) + { + if ( !is_player_valid( player ) ) + { + continue; + } + if ( player hasperk("specialty_quickrevive" ) ) + { + if ( !isdefined( player.lives ) ) + { + player.lives = 0; + } + if ( !isdefined( level.solo_lives_given ) ) + { + level.solo_lives_given = 0; + } + level.solo_lives_given++; + player.lives++; + if ( isdefined( player.lives ) && player.lives > 0 && power_state ) + { + should_pause = 0; + } + should_pause = 1; + } + } + if ( should_pause ) + { + perk_pause( "specialty_quickrevive" ); + } + else + { + perk_unpause( "specialty_quickrevive" ); + } +} + +update_quickrevive_power_state( poweron ) //checked matches cerberus output +{ + foreach ( item in level.powered_items ) + { + if ( isdefined( item.target ) && isdefined( item.target.script_noteworthy ) && item.target.script_noteworthy == "specialty_quickrevive" ) + { + if ( item.power && !poweron ) + { + if ( !isdefined( item.powered_count ) ) + { + item.powered_count = 0; + } + else if ( item.powered_count > 0 ) + { + item.powered_count--; + } + } + else if ( !item.power && poweron ) + { + if ( !isdefined( item.powered_count ) ) + { + item.powered_count = 0; + } + item.powered_count++; + } + if ( !isdefined( item.depowered_count ) ) + { + item.depowered_count = 0; + } + item.power = poweron; + } + } +} + +restart_quickrevive() //checked changed to match cerberus output //changed at own discretion +{ + triggers = getentarray( "zombie_vending", "targetname" ); + foreach ( trigger in triggers ) + { + if ( trigger.script_noteworthy == "specialty_quickrevive" || trigger.script_noteworthy == "specialty_quickrevive_upgrade" ) + { + trigger notify( "stop_quickrevive_logic" ); + trigger thread vending_trigger_think(); + trigger trigger_on(); + } + } +} + +disable_quickrevive( machine_clip ) //checked changed to match cerberus output +{ + if ( is_true( level.solo_revive_init ) && flag( "solo_revive" ) && isDefined( level.quick_revive_machine ) ) + { + triggers = getentarray( "zombie_vending", "targetname" ); + foreach ( trigger in triggers ) + { + if ( !isdefined( trigger.script_noteworthy ) ) + { + continue; + } + if ( trigger.script_noteworthy == "specialty_quickrevive" || trigger.script_noteworthy == "specialty_quickrevive_upgrade" ) + { + trigger trigger_off(); + } + } + foreach ( item in level.powered_items ) + { + if ( isdefined( item.target ) && isdefined( item.target.script_noteworthy ) && item.target.script_noteworthy == "specialty_quickrevive" ) + { + item.power = 1; + item.self_powered = 1; + } + } + if ( isDefined( level.quick_revive_machine.original_pos ) ) + { + level.quick_revive_default_origin = level.quick_revive_machine.original_pos; + level.quick_revive_default_angles = level.quick_revive_machine.original_angles; + } + move_org = level.quick_revive_default_origin; + if ( isDefined( level.quick_revive_linked_ent ) ) + { + move_org = level.quick_revive_linked_ent.origin; + if ( isDefined( level.quick_revive_linked_ent_offset ) ) + { + move_org += level.quick_revive_linked_ent_offset; + } + level.quick_revive_machine unlink(); + } + level.quick_revive_machine moveto( move_org + vectorScale( ( 0, 0, 1 ), 40 ), 3 ); + direction = level.quick_revive_machine.origin; + direction = ( direction[ 1 ], direction[ 0 ], 0 ); + if ( direction[ 1 ] < 0 || direction[ 0 ] > 0 && direction[ 1 ] > 0 ) + { + direction = ( direction[ 0 ], direction[ 1 ] * -1, 0 ); + } + else + { + if ( direction[ 0 ] < 0 ) + { + direction = ( direction[ 0 ] * -1, direction[ 1 ], 0 ); + } + } + level.quick_revive_machine vibrate( direction, 10, 0.5, 4 ); + level.quick_revive_machine waittill( "movedone" ); + level.quick_revive_machine hide(); + level.quick_revive_machine.ishidden = 1; + if ( isDefined( level.quick_revive_machine_clip ) ) + { + level.quick_revive_machine_clip connectpaths(); + level.quick_revive_machine_clip trigger_off(); + } + playfx( level._effect[ "poltergeist" ], level.quick_revive_machine.origin ); + if ( isDefined( level.quick_revive_trigger ) && isDefined( level.quick_revive_trigger.blocker_model ) ) + { + level.quick_revive_trigger.blocker_model show(); + } + level notify( "revive_hide" ); + } +} + +unhide_quickrevive() //checked matches cerberus output +{ + while ( players_are_in_perk_area( level.quick_revive_machine ) ) + { + wait 0.1; + } + if ( isDefined( level.quick_revive_machine_clip ) ) + { + level.quick_revive_machine_clip trigger_on(); + level.quick_revive_machine_clip disconnectpaths(); + } + if ( isDefined( level.quick_revive_final_pos ) ) + { + level.quick_revive_machine.origin = level.quick_revive_final_pos; + } + playfx( level._effect[ "poltergeist" ], level.quick_revive_machine.origin ); + if ( isDefined( level.quick_revive_trigger ) && isDefined( level.quick_revive_trigger.blocker_model ) ) + { + level.quick_revive_trigger.blocker_model hide(); + } + level.quick_revive_machine show(); + if ( isDefined( level.quick_revive_machine.original_pos ) ) + { + level.quick_revive_default_origin = level.quick_revive_machine.original_pos; + level.quick_revive_default_angles = level.quick_revive_machine.original_angles; + } + direction = level.quick_revive_machine.origin; + direction = ( direction[ 1 ], direction[ 0 ], 0 ); + if ( direction[ 1 ] < 0 || direction[ 0 ] > 0 && direction[ 1 ] > 0 ) + { + direction = ( direction[ 0 ], direction[ 1 ] * -1, 0 ); + } + else + { + if ( direction[ 0 ] < 0 ) + { + direction = ( direction[ 0 ] * -1, direction[ 1 ], 0 ); + } + } + org = level.quick_revive_default_origin; + if ( isDefined( level.quick_revive_linked_ent ) ) + { + org = level.quick_revive_linked_ent.origin; + if ( isDefined( level.quick_revive_linked_ent_offset ) ) + { + org += level.quick_revive_linked_ent_offset; + } + } + if ( !is_true( level.quick_revive_linked_ent_moves ) && level.quick_revive_machine.origin != org ) + { + level.quick_revive_machine moveto( org, 3 ); + level.quick_revive_machine vibrate( direction, 10, 0.5, 2.9 ); + level.quick_revive_machine waittill( "movedone" ); + level.quick_revive_machine.angles = level.quick_revive_default_angles; + } + else + { + if ( isDefined( level.quick_revive_linked_ent ) ) + { + org = level.quick_revive_linked_ent.origin; + if ( isDefined( level.quick_revive_linked_ent_offset ) ) + { + org += level.quick_revive_linked_ent_offset; + } + level.quick_revive_machine.origin = org; + } + level.quick_revive_machine vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0.3, 0.4, 3 ); + } + if ( isDefined( level.quick_revive_linked_ent ) ) + { + level.quick_revive_machine linkto( level.quick_revive_linked_ent ); + } + level.quick_revive_machine.ishidden = 0; +} + +players_are_in_perk_area( perk_machine ) //checked changed to match cerberus output +{ + perk_area_origin = level.quick_revive_default_origin; + if ( isDefined( perk_machine._linked_ent ) ) + { + perk_area_origin = perk_machine._linked_ent.origin; + if ( isDefined( perk_machine._linked_ent_offset ) ) + { + perk_area_origin += perk_machine._linked_ent_offset; + } + } + in_area = 0; + players = get_players(); + dist_check = 9216; + foreach ( player in players ) + { + if ( distancesquared( player.origin, perk_area_origin ) < dist_check ) + { + return 1; + } + } + return 0; +} + +perk_hostmigration() //checked changed to match cerberus output +{ + level endon( "end_game" ); + level notify( "perk_hostmigration" ); + level endon( "perk_hostmigration" ); + while ( 1 ) + { + level waittill( "host_migration_end" ); + jug = getentarray( "vending_jugg", "targetname" ); + tap = getentarray( "vending_doubletap", "targetname" ); + mar = getentarray( "vending_marathon", "targetname" ); + deadshot = getentarray( "vending_deadshot", "targetname" ); + tomb = getentarray( "vending_tombstone", "targetname" ); + extraweap = getentarray( "vending_additionalprimaryweapon", "targetname" ); + sleight = getentarray( "vending_sleight", "targetname" ); + revive = getentarray( "vending_revive", "targetname" ); + chugabud = getentarray( "vending_chugabud", "targetname" ); + foreach ( perk in jug ) + { + if ( isdefined( perk.model ) && perk.model == level.machine_assets[ "juggernog" ].on_model ) + { + perk perk_fx( undefined, 1 ); + perk thread perk_fx( "jugger_light" ); + } + } + foreach ( perk in tap ) + { + if ( isdefined( perk.model ) && perk.model == level.machine_assets[ "doubletap" ].on_model ) + { + perk perk_fx(undefined, 1); + perk thread perk_fx("doubletap_light"); + } + } + foreach ( perk in mar ) + { + if ( isdefined( perk.model ) && perk.model == level.machine_assets[ "marathon" ].on_model ) + { + perk perk_fx( undefined, 1 ); + perk thread perk_fx( "marathon_light" ); + } + } + foreach ( perk in deadshot ) + { + if ( isdefined( perk.model ) && perk.model == level.machine_assets[ "deadshot" ].on_model ) + { + perk perk_fx( undefined, 1 ); + perk thread perk_fx( "deadshot_light" ); + } + } + foreach ( perk in tomb ) + { + if ( isdefined( perk.model ) && perk.model == level.machine_assets[ "tombstone" ].on_model ) + { + perk perk_fx( undefined, 1 ); + perk thread perk_fx( "tombstone_light" ); + } + } + foreach ( perk in extraweap ) + { + if ( isdefined( perk.model ) && perk.model == level.machine_assets[ "additionalprimaryweapon" ].on_model ) + { + perk perk_fx( undefined, 1 ); + perk thread perk_fx( "additionalprimaryweapon_light" ); + } + } + foreach(perk in sleight) + { + if ( isdefined( perk.model ) && perk.model == level.machine_assets[ "speedcola" ].on_model ) + { + perk perk_fx( undefined, 1 ); + perk thread perk_fx( "sleight_light" ); + } + } + foreach ( perk in revive ) + { + if ( isdefined( perk.model ) && perk.model == level.machine_assets[ "revive" ].on_model ) + { + perk perk_fx( undefined, 1 ); + perk thread perk_fx( "revive_light" ); + } + } + foreach ( perk in chugabud ) + { + if ( isdefined( perk.model ) && perk.model == level.machine_assets[ "revive" ].on_model ) + { + perk perk_fx( undefined, 1 ); + perk thread perk_fx( "tombstone_light" ); + } + } + if ( level._custom_perks.size > 0 ) + { + a_keys = getarraykeys( level._custom_perks ); + for ( i = 0; i < a_keys.size; i++ ) + { + if ( isdefined( level._custom_perks[ a_keys[ i ] ].host_migration_func ) ) + { + level thread [[ level._custom_perks[ a_keys[ i ] ].host_migration_func ]](); + } + } + } + } +} + +get_perk_array( ignore_chugabud ) //checked matches cerberus output +{ + perk_array = []; + if ( self hasperk( "specialty_armorvest" ) ) + { + perk_array[ perk_array.size ] = "specialty_armorvest"; + } + if ( self hasperk( "specialty_deadshot" ) ) + { + perk_array[ perk_array.size ] = "specialty_deadshot"; + } + if ( self hasperk( "specialty_fastreload" ) ) + { + perk_array[ perk_array.size ] = "specialty_fastreload"; + } + if ( self hasperk( "specialty_flakjacket" ) ) + { + perk_array[ perk_array.size ] = "specialty_flakjacket"; + } + if ( self hasperk( "specialty_longersprint" ) ) + { + perk_array[ perk_array.size ] = "specialty_longersprint"; + } + if ( self hasperk( "specialty_quickrevive" ) ) + { + perk_array[ perk_array.size ] = "specialty_quickrevive"; + } + if ( self hasperk( "specialty_rof" ) ) + { + perk_array[ perk_array.size ] = "specialty_rof"; + } + if ( self hasperk( "specialty_additionalprimaryweapon" ) ) + { + perk_array[ perk_array.size ] = "specialty_additionalprimaryweapon"; + } + if ( !isDefined( ignore_chugabud ) || ignore_chugabud == 0 ) + { + if ( self hasperk( "specialty_finalstand" ) ) + { + perk_array[ perk_array.size ] = "specialty_finalstand"; + } + } + if ( level._custom_perks.size > 0 ) + { + a_keys = getarraykeys( level._custom_perks ); + for ( i = 0; i < a_keys.size; i++ ) + { + if ( self hasperk( a_keys[ i ] ) ) + { + perk_array[ perk_array.size ] = a_keys[ i ]; + } + } + } + return perk_array; +} + +initialize_custom_perk_arrays() //checked matches cerberus output +{ + if ( !isDefined( level._custom_perks ) ) + { + level._custom_perks = []; + } +} + +register_perk_basic_info( str_perk, str_alias, n_perk_cost, str_hint_string, str_perk_bottle_weapon ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( str_perk ), "str_perk is a required argument for register_perk_basic_info!" ); +#/ +/# + assert( isDefined( str_alias ), "str_alias is a required argument for register_perk_basic_info!" ); +#/ +/# + assert( isDefined( n_perk_cost ), "n_perk_cost is a required argument for register_perk_basic_info!" ); +#/ +/# + assert( isDefined( str_hint_string ), "str_hint_string is a required argument for register_perk_basic_info!" ); +#/ +/# + assert( isDefined( str_perk_bottle_weapon ), "str_perk_bottle_weapon is a required argument for register_perk_basic_info!" ); +#/ +*/ + _register_undefined_perk( str_perk ); + level._custom_perks[ str_perk ].alias = str_perk; + level._custom_perks[ str_perk ].cost = n_perk_cost; + level._custom_perks[ str_perk ].hint_string = str_hint_string; + level._custom_perks[ str_perk ].perk_bottle = str_perk_bottle_weapon; +} + +register_perk_machine( str_perk, func_perk_machine_setup, func_perk_machine_thread ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( str_perk ), "str_perk is a required argument for register_perk_machine!" ); +#/ +/# + assert( isDefined( func_perk_machine_setup ), "func_perk_machine_setup is a required argument for register_perk_machine!" ); +#/ +/# + assert( isDefined( func_perk_machine_thread ), "func_perk_machine_thread is a required argument for register_perk_machine!" ); +#/ +*/ + _register_undefined_perk( str_perk ); + if ( !isDefined( level._custom_perks[ str_perk ].perk_machine_set_kvps ) ) + { + level._custom_perks[ str_perk ].perk_machine_set_kvps = func_perk_machine_setup; + } + if ( !isDefined( level._custom_perks[ str_perk ].perk_machine_thread ) ) + { + level._custom_perks[ str_perk ].perk_machine_thread = func_perk_machine_thread; + } +} + +register_perk_precache_func( str_perk, func_precache ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( str_perk ), "str_perk is a required argument for register_perk_precache_func!" ); +#/ +/# + assert( isDefined( func_precache ), "func_precache is a required argument for register_perk_precache_func!" ); +#/ +*/ + _register_undefined_perk( str_perk ); + if ( !isDefined( level._custom_perks[ str_perk ].precache_func ) ) + { + level._custom_perks[ str_perk ].precache_func = func_precache; + } +} + +register_perk_threads( str_perk, func_give_player_perk, func_take_player_perk ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( str_perk ), "str_perk is a required argument for register_perk_threads!" ); +#/ +/# + assert( isDefined( func_give_player_perk ), "func_give_player_perk is a required argument for register_perk_threads!" ); +#/ +*/ + _register_undefined_perk( str_perk ); + if ( !isDefined( level._custom_perks[ str_perk ].player_thread_give ) ) + { + level._custom_perks[ str_perk ].player_thread_give = func_give_player_perk; + } + if ( isDefined( func_take_player_perk ) ) + { + if ( !isDefined( level._custom_perks[ str_perk ].player_thread_take ) ) + { + level._custom_perks[ str_perk ].player_thread_take = func_take_player_perk; + } + } +} + +register_perk_clientfields( str_perk, func_clientfield_register, func_clientfield_set ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( str_perk ), "str_perk is a required argument for register_perk_clientfields!" ); +#/ +/# + assert( isDefined( func_clientfield_register ), "func_clientfield_register is a required argument for register_perk_clientfields!" ); +#/ +/# + assert( isDefined( func_clientfield_set ), "func_clientfield_set is a required argument for register_perk_clientfields!" ); +#/ +*/ + _register_undefined_perk( str_perk ); + if ( !isDefined( level._custom_perks[ str_perk ].clientfield_register ) ) + { + level._custom_perks[ str_perk ].clientfield_register = func_clientfield_register; + } + if ( !isDefined( level._custom_perks[ str_perk ].clientfield_set ) ) + { + level._custom_perks[ str_perk ].clientfield_set = func_clientfield_set; + } +} + +register_perk_host_migration_func( str_perk, func_host_migration ) //checked matches cerberus output +{ +/* +/# + assert( isDefined( str_perk ), "str_perk is a required argument for register_perk_host_migration_func!" ); +#/ +/# + assert( isDefined( func_host_migration ), "func_host_migration is a required argument for register_perk_host_migration_func!" ); +#/ +*/ + _register_undefined_perk( str_perk ); + if ( !isDefined( level._custom_perks[ str_perk ].host_migration_func ) ) + { + level._custom_perks[ str_perk ].host_migration_func = func_host_migration; + } +} + +_register_undefined_perk( str_perk ) //checked matches cerberus output +{ + if ( !isDefined( level._custom_perks ) ) + { + level._custom_perks = []; + } + if ( !isDefined( level._custom_perks[ str_perk ] ) ) + { + level._custom_perks[ str_perk ] = spawnstruct(); + } +} + + + + + + + + + + + + + + + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_powerups.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_powerups.gsc new file mode 100644 index 0000000..dda66fe --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_powerups.gsc @@ -0,0 +1,2862 @@ +#include maps/mp/zombies/_zm_melee_weapon; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_perks; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/zombies/_zm_pers_upgrades_functions; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/animscripts/zm_death; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_blockers; +#include maps/mp/zombies/_zm_audio_announcer; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_pers_upgrades; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/_demo; +#include maps/mp/zombies/_zm_magicbox; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() //checked matches cerberus output +{ + precacheshader( "specialty_doublepoints_zombies" ); + precacheshader( "specialty_instakill_zombies" ); + precacheshader( "specialty_firesale_zombies" ); + precacheshader( "zom_icon_bonfire" ); + precacheshader( "zom_icon_minigun" ); + precacheshader( "black" ); + set_zombie_var( "zombie_insta_kill", 0, undefined, undefined, 1 ); + set_zombie_var( "zombie_point_scalar", 1, undefined, undefined, 1 ); + set_zombie_var( "zombie_drop_item", 0 ); + set_zombie_var( "zombie_timer_offset", 350 ); + set_zombie_var( "zombie_timer_offset_interval", 30 ); + set_zombie_var( "zombie_powerup_fire_sale_on", 0 ); + set_zombie_var( "zombie_powerup_fire_sale_time", 30 ); + set_zombie_var( "zombie_powerup_bonfire_sale_on", 0 ); + set_zombie_var( "zombie_powerup_bonfire_sale_time", 30 ); + set_zombie_var( "zombie_powerup_insta_kill_on", 0, undefined, undefined, 1 ); + set_zombie_var( "zombie_powerup_insta_kill_time", 30, undefined, undefined, 1 ); + set_zombie_var( "zombie_powerup_point_doubler_on", 0, undefined, undefined, 1 ); + set_zombie_var( "zombie_powerup_point_doubler_time", 30, undefined, undefined, 1 ); + set_zombie_var( "zombie_powerup_drop_increment", 2000 ); + set_zombie_var( "zombie_powerup_drop_max_per_round", 4 ); + onplayerconnect_callback( ::init_player_zombie_vars ); + level._effect[ "powerup_on" ] = loadfx( "misc/fx_zombie_powerup_on" ); + level._effect[ "powerup_off" ] = loadfx( "misc/fx_zombie_powerup_off" ); + level._effect[ "powerup_grabbed" ] = loadfx( "misc/fx_zombie_powerup_grab" ); + level._effect[ "powerup_grabbed_wave" ] = loadfx( "misc/fx_zombie_powerup_wave" ); + if ( is_true( level.using_zombie_powerups ) ) + { + level._effect[ "powerup_on_red" ] = loadfx( "misc/fx_zombie_powerup_on_red" ); + level._effect[ "powerup_grabbed_red" ] = loadfx( "misc/fx_zombie_powerup_red_grab" ); + level._effect[ "powerup_grabbed_wave_red" ] = loadfx( "misc/fx_zombie_powerup_red_wave" ); + } + level._effect[ "powerup_on_solo" ] = loadfx( "misc/fx_zombie_powerup_solo_on" ); + level._effect[ "powerup_grabbed_solo" ] = loadfx( "misc/fx_zombie_powerup_solo_grab" ); + level._effect[ "powerup_grabbed_wave_solo" ] = loadfx( "misc/fx_zombie_powerup_solo_wave" ); + level._effect[ "powerup_on_caution" ] = loadfx( "misc/fx_zombie_powerup_caution_on" ); + level._effect[ "powerup_grabbed_caution" ] = loadfx( "misc/fx_zombie_powerup_caution_grab" ); + level._effect[ "powerup_grabbed_wave_caution" ] = loadfx( "misc/fx_zombie_powerup_caution_wave" ); + init_powerups(); + if ( !level.enable_magic ) + { + return; + } + thread watch_for_drop(); + thread setup_firesale_audio(); + thread setup_bonfiresale_audio(); + level.use_new_carpenter_func = ::start_carpenter_new; + level.board_repair_distance_squared = 562500; +} + +init_powerups() //checked matches cerberus output +{ + flag_init( "zombie_drop_powerups" ); + if ( is_true( level.enable_magic ) ) + { + flag_set( "zombie_drop_powerups" ); + } + if ( !isDefined( level.active_powerups ) ) + { + level.active_powerups = []; + } + if ( !isDefined( level.zombie_powerup_array ) ) + { + level.zombie_powerup_array = []; + } + if ( !isDefined( level.zombie_special_drop_array ) ) + { + level.zombie_special_drop_array = []; + } + add_zombie_powerup( "nuke", "zombie_bomb", &"ZOMBIE_POWERUP_NUKE", ::func_should_always_drop, 0, 0, 0, "misc/fx_zombie_mini_nuke_hotness" ); + add_zombie_powerup( "insta_kill", "zombie_skull", &"ZOMBIE_POWERUP_INSTA_KILL", ::func_should_always_drop, 0, 0, 0, undefined, "powerup_instant_kill", "zombie_powerup_insta_kill_time", "zombie_powerup_insta_kill_on" ); + add_zombie_powerup( "full_ammo", "zombie_ammocan", &"ZOMBIE_POWERUP_MAX_AMMO", ::func_should_always_drop, 0, 0, 0 ); + add_zombie_powerup( "double_points", "zombie_x2_icon", &"ZOMBIE_POWERUP_DOUBLE_POINTS", ::func_should_always_drop, 0, 0, 0, undefined, "powerup_double_points", "zombie_powerup_point_doubler_time", "zombie_powerup_point_doubler_on" ); + add_zombie_powerup( "carpenter", "zombie_carpenter", &"ZOMBIE_POWERUP_MAX_AMMO", ::func_should_drop_carpenter, 0, 0, 0 ); + add_zombie_powerup( "fire_sale", "zombie_firesale", &"ZOMBIE_POWERUP_MAX_AMMO", ::func_should_drop_fire_sale, 0, 0, 0, undefined, "powerup_fire_sale", "zombie_powerup_fire_sale_time", "zombie_powerup_fire_sale_on" ); + add_zombie_powerup( "bonfire_sale", "zombie_pickup_bonfire", &"ZOMBIE_POWERUP_MAX_AMMO", ::func_should_never_drop, 0, 0, 0, undefined, "powerup_bon_fire", "zombie_powerup_bonfire_sale_time", "zombie_powerup_bonfire_sale_on" ); + add_zombie_powerup( "minigun", "zombie_pickup_minigun", &"ZOMBIE_POWERUP_MINIGUN", ::func_should_drop_minigun, 1, 0, 0, undefined, "powerup_mini_gun", "zombie_powerup_minigun_time", "zombie_powerup_minigun_on" ); + add_zombie_powerup( "free_perk", "zombie_pickup_perk_bottle", &"ZOMBIE_POWERUP_FREE_PERK", ::func_should_never_drop, 0, 0, 0 ); + add_zombie_powerup( "tesla", "zombie_pickup_minigun", &"ZOMBIE_POWERUP_MINIGUN", ::func_should_never_drop, 1, 0, 0, undefined, "powerup_tesla", "zombie_powerup_tesla_time", "zombie_powerup_tesla_on" ); + add_zombie_powerup( "random_weapon", "zombie_pickup_minigun", &"ZOMBIE_POWERUP_MAX_AMMO", ::func_should_never_drop, 1, 0, 0 ); + add_zombie_powerup( "bonus_points_player", "zombie_z_money_icon", &"ZOMBIE_POWERUP_BONUS_POINTS", ::func_should_never_drop, 1, 0, 0 ); + add_zombie_powerup( "bonus_points_team", "zombie_z_money_icon", &"ZOMBIE_POWERUP_BONUS_POINTS", ::func_should_never_drop, 0, 0, 0 ); + add_zombie_powerup( "lose_points_team", "zombie_z_money_icon", &"ZOMBIE_POWERUP_LOSE_POINTS", ::func_should_never_drop, 0, 0, 1 ); + add_zombie_powerup( "lose_perk", "zombie_pickup_perk_bottle", &"ZOMBIE_POWERUP_MAX_AMMO", ::func_should_never_drop, 0, 0, 1 ); + add_zombie_powerup( "empty_clip", "zombie_ammocan", &"ZOMBIE_POWERUP_MAX_AMMO", ::func_should_never_drop, 0, 0, 1 ); + add_zombie_powerup( "insta_kill_ug", "zombie_skull", &"ZOMBIE_POWERUP_INSTA_KILL", ::func_should_never_drop, 1, 0, 0, undefined, "powerup_instant_kill_ug", "zombie_powerup_insta_kill_ug_time", "zombie_powerup_insta_kill_ug_on", 5000 ); + if ( isDefined( level.level_specific_init_powerups ) ) + { + [[ level.level_specific_init_powerups ]](); + } + randomize_powerups(); + level.zombie_powerup_index = 0; + randomize_powerups(); + level.rare_powerups_active = 0; + level.firesale_vox_firstime = 0; + level thread powerup_hud_monitor(); + if ( isDefined( level.quantum_bomb_register_result_func ) ) + { + [[ level.quantum_bomb_register_result_func ]]( "random_powerup", ::quantum_bomb_random_powerup_result, 5, level.quantum_bomb_in_playable_area_validation_func ); + [[ level.quantum_bomb_register_result_func ]]( "random_zombie_grab_powerup", ::quantum_bomb_random_zombie_grab_powerup_result, 5, level.quantum_bomb_in_playable_area_validation_func ); + [[ level.quantum_bomb_register_result_func ]]( "random_weapon_powerup", ::quantum_bomb_random_weapon_powerup_result, 60, level.quantum_bomb_in_playable_area_validation_func ); + [[ level.quantum_bomb_register_result_func ]]( "random_bonus_or_lose_points_powerup", ::quantum_bomb_random_bonus_or_lose_points_powerup_result, 25, level.quantum_bomb_in_playable_area_validation_func ); + } + registerclientfield( "scriptmover", "powerup_fx", 1000, 3, "int" ); +} + +init_player_zombie_vars() //checked matches cerberus output +{ + self.zombie_vars[ "zombie_powerup_minigun_on" ] = 0; + self.zombie_vars[ "zombie_powerup_minigun_time" ] = 0; + self.zombie_vars[ "zombie_powerup_tesla_on" ] = 0; + self.zombie_vars[ "zombie_powerup_tesla_time" ] = 0; + self.zombie_vars[ "zombie_powerup_insta_kill_ug_on" ] = 0; + self.zombie_vars[ "zombie_powerup_insta_kill_ug_time" ] = 18; +} + +set_weapon_ignore_max_ammo( str_weapon ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_weapons_no_max_ammo ) ) + { + level.zombie_weapons_no_max_ammo = []; + } + level.zombie_weapons_no_max_ammo[ str_weapon ] = 1; +} + +powerup_hud_monitor() //checked partially changed to match cerberus output +{ + flag_wait( "start_zombie_round_logic" ); + if ( isDefined( level.current_game_module ) && level.current_game_module == 2 ) + { + return; + } + flashing_timers = []; + flashing_values = []; + flashing_timer = 10; + flashing_delta_time = 0; + flashing_is_on = 0; + flashing_value = 3; + flashing_min_timer = 0.15; + while ( flashing_timer >= flashing_min_timer ) + { + if ( flashing_timer < 5 ) + { + flashing_delta_time = 0.1; + } + else + { + flashing_delta_time = 0.2; + } + if ( flashing_is_on ) + { + flashing_timer = flashing_timer - flashing_delta_time - 0.05; + flashing_value = 2; + } + else + { + flashing_timer -= flashing_delta_time; + flashing_value = 3; + } + flashing_timers[ flashing_timers.size ] = flashing_timer; + flashing_values[ flashing_values.size ] = flashing_value; + flashing_is_on = !flashing_is_on; + } + client_fields = []; + powerup_keys = getarraykeys( level.zombie_powerups ); + for ( powerup_key_index = 0; powerup_key_index < powerup_keys.size; powerup_key_index++ ) + { + if ( isDefined( level.zombie_powerups[ powerup_keys[ powerup_key_index ] ].client_field_name ) ) + { + powerup_name = powerup_keys[ powerup_key_index ]; + client_fields[ powerup_name ] = spawnstruct(); + client_fields[ powerup_name ].client_field_name = level.zombie_powerups[ powerup_name ].client_field_name; + client_fields[ powerup_name ].solo = level.zombie_powerups[ powerup_name ].solo; + client_fields[ powerup_name ].time_name = level.zombie_powerups[ powerup_name ].time_name; + client_fields[ powerup_name ].on_name = level.zombie_powerups[ powerup_name ].on_name; + } + } + client_field_keys = getarraykeys( client_fields ); + + while ( 1 ) + { + wait 0.05; + waittillframeend; + players = get_players(); + + for ( playerindex = 0; playerindex < players.size; playerindex++ ) + { + client_field_key_index = 0; + while ( client_field_key_index < client_field_keys.size ) + { + + player = players[ playerindex ]; + if ( isdefined(level.powerup_player_valid ) ) + { + if ( ![[ level.powerup_player_valid ]]( player ) ) + { + client_field_key_index++; + continue; + } + } + + client_field_name = client_fields[ client_field_keys[ client_field_key_index ] ].client_field_name; + time_name = client_fields[ client_field_keys[ client_field_key_index ] ].time_name; + on_name = client_fields[ client_field_keys[ client_field_key_index ] ].on_name; + powerup_timer = undefined; + powerup_on = undefined; + if ( client_fields[ client_field_keys[ client_field_key_index ] ].solo ) + { + if ( isdefined( player._show_solo_hud ) && player._show_solo_hud == 1 ) + { + powerup_timer = player.zombie_vars[ time_name ]; + powerup_on = player.zombie_vars[ on_name ]; + } + } + + else if ( isdefined( level.zombie_vars[ player.team ][ time_name ] ) ) + { + powerup_timer = level.zombie_vars[ player.team ][ time_name ]; + powerup_on = level.zombie_vars[ player.team ][on_name ]; + } + else if ( isdefined( level.zombie_vars[ time_name ] ) ) + { + powerup_timer = level.zombie_vars[ time_name ]; + powerup_on = level.zombie_vars[ on_name ]; + } + + if ( isdefined( powerup_timer ) && isdefined( powerup_on ) ) + { + player set_clientfield_powerups( client_field_name, powerup_timer, powerup_on, flashing_timers, flashing_values ); + } + else + { + player setclientfieldtoplayer( client_field_name, 0 ); + } + client_field_key_index++; + } + } + + } +} + +set_clientfield_powerups( clientfield_name, powerup_timer, powerup_on, flashing_timers, flashing_values ) //checked changed to match cerberus output +{ + if ( powerup_on ) + { + if ( powerup_timer < 10 ) + { + flashing_value = 3; + for ( i = flashing_timers.size - 1; i > 0; i-- ) + { + if ( powerup_timer < flashing_timers[ i ] ) + { + flashing_value = flashing_values[ i ]; + break; + } + } + self setclientfieldtoplayer( clientfield_name, flashing_value ); + } + else + { + self setclientfieldtoplayer( clientfield_name, 1 ); + } + } + else + { + self setclientfieldtoplayer( clientfield_name, 0 ); + } +} + +randomize_powerups() //checked matches cerberus output +{ + level.zombie_powerup_array = array_randomize( level.zombie_powerup_array ); +} + +get_next_powerup() //checked matches cerberus output +{ + powerup = level.zombie_powerup_array[ level.zombie_powerup_index ]; + level.zombie_powerup_index++; + if ( level.zombie_powerup_index >= level.zombie_powerup_array.size ) + { + level.zombie_powerup_index = 0; + randomize_powerups(); + } + return powerup; +} + +get_valid_powerup() //checked partially matches cerberus output did not change +{ + if ( isDefined( level.zombie_powerup_boss ) ) + { + i = level.zombie_powerup_boss; + level.zombie_powerup_boss = undefined; + return level.zombie_powerup_array[ i ]; + } + if ( isDefined( level.zombie_powerup_ape ) ) + { + powerup = level.zombie_powerup_ape; + level.zombie_powerup_ape = undefined; + return powerup; + } + powerup = get_next_powerup(); + while ( 1 ) + { + while ( !( [[ level.zombie_powerups[ powerup ].func_should_drop_with_regular_powerups ]]() ) ) + { + powerup = get_next_powerup(); + } + return powerup; + } +} + +minigun_no_drop() //checked matches cerberus output +{ + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ].zombie_vars[ "zombie_powerup_minigun_on" ] == 1 ) + { + return 1; + } + i++; + } + if ( !flag( "power_on" ) ) + { + if ( flag( "solo_game" ) ) + { + if ( level.solo_lives_given == 0 ) + { + return 1; + } + } + else + { + return 1; + } + } + return 0; +} + +get_num_window_destroyed() //checked partially matches cerberus output did not change +{ + num = 0; + for ( i = 0; i < level.exterior_goals.size; i++ ) + { + if ( all_chunks_destroyed( level.exterior_goals[ i ], level.exterior_goals[ i ].barrier_chunks ) ) + { + num += 1; + } + } + return num; +} + +watch_for_drop() //checked partially matches cerberus output did not change +{ + flag_wait( "start_zombie_round_logic" ); + flag_wait( "begin_spawning" ); + players = get_players(); + score_to_drop = ( players.size * level.zombie_vars[ "zombie_score_start_" + players.size + "p" ] ) + level.zombie_vars[ "zombie_powerup_drop_increment" ]; + while ( 1 ) + { + flag_wait( "zombie_drop_powerups" ); + players = get_players(); + curr_total_score = 0; + for ( i = 0; i < players.size; i++ ) + { + if ( isDefined( players[ i ].score_total ) ) + { + curr_total_score += players[ i ].score_total; + } + } + if ( curr_total_score > score_to_drop ) + { + level.zombie_vars[ "zombie_powerup_drop_increment" ] *= 1.14; + score_to_drop = curr_total_score + level.zombie_vars[ "zombie_powerup_drop_increment" ]; + level.zombie_vars[ "zombie_drop_item" ] = 1; + } + wait 0.5; + } + +} + +add_zombie_powerup( powerup_name, model_name, hint, func_should_drop_with_regular_powerups, solo, caution, zombie_grabbable, fx, client_field_name, time_name, on_name, clientfield_version ) //checked matches cerberus output +{ + if ( !isDefined( clientfield_version ) ) + { + clientfield_version = 1; + } + if ( isDefined( level.zombie_include_powerups ) && !isDefined( level.zombie_include_powerups[ powerup_name ] ) ) + { + return; + } + precachemodel( model_name ); + precachestring( hint ); + struct = spawnstruct(); + if ( !isDefined( level.zombie_powerups ) ) + { + level.zombie_powerups = []; + } + struct.powerup_name = powerup_name; + struct.model_name = model_name; + struct.weapon_classname = "script_model"; + struct.hint = hint; + struct.func_should_drop_with_regular_powerups = func_should_drop_with_regular_powerups; + struct.solo = solo; + struct.caution = caution; + struct.zombie_grabbable = zombie_grabbable; + if ( isDefined( fx ) ) + { + struct.fx = loadfx( fx ); + } + level.zombie_powerups[ powerup_name ] = struct; + level.zombie_powerup_array[ level.zombie_powerup_array.size ] = powerup_name; + add_zombie_special_drop( powerup_name ); + if ( !level.createfx_enabled ) + { + if ( isDefined( client_field_name ) ) + { + registerclientfield( "toplayer", client_field_name, clientfield_version, 2, "int" ); + struct.client_field_name = client_field_name; + struct.time_name = time_name; + struct.on_name = on_name; + } + } +} + +powerup_set_can_pick_up_in_last_stand( powerup_name, b_can_pick_up ) //checked matches cerberus output +{ + level.zombie_powerups[ powerup_name ].can_pick_up_in_last_stand = b_can_pick_up; +} + +add_zombie_special_drop( powerup_name ) //checked matches cerberus output +{ + level.zombie_special_drop_array[ level.zombie_special_drop_array.size ] = powerup_name; +} + +include_zombie_powerup( powerup_name ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_include_powerups ) ) + { + level.zombie_include_powerups = []; + } + level.zombie_include_powerups[ powerup_name ] = 1; +} + +powerup_round_start() //checked matches cerberus output +{ + level.powerup_drop_count = 0; +} + +powerup_drop( drop_point ) //checked partially changed to match cerberus output +{ + if ( level.powerup_drop_count >= level.zombie_vars[ "zombie_powerup_drop_max_per_round" ] ) + { + return; + } + if ( !isDefined( level.zombie_include_powerups ) || level.zombie_include_powerups.size == 0 ) + { + return; + } + rand_drop = randomint( 100 ); + if ( rand_drop > 2 ) + { + if ( !level.zombie_vars[ "zombie_drop_item" ] ) + { + return; + } + debug = "score"; + } + else + { + debug = "random"; + } + playable_area = getentarray( "player_volume", "script_noteworthy" ); + level.powerup_drop_count++; + powerup = maps/mp/zombies/_zm_net::network_safe_spawn( "powerup", 1, "script_model", drop_point + vectorScale( ( 0, 0, 1 ), 40 ) ); + valid_drop = 0; + for ( i = 0; i < playable_area.size; i++ ) + { + if ( powerup istouching( playable_area[ i ] ) ) + { + valid_drop = 1; + break; + } + } + if ( valid_drop && level.rare_powerups_active ) + { + pos = ( drop_point[ 0 ], drop_point[ 1 ], drop_point[ 2 ] + 42 ); + if ( check_for_rare_drop_override( pos ) ) + { + level.zombie_vars[ "zombie_drop_item" ] = 0; + valid_drop = 0; + } + } + if ( !valid_drop ) + { + level.powerup_drop_count--; + + powerup delete(); + return; + } + powerup powerup_setup(); + print_powerup_drop( powerup.powerup_name, debug ); + powerup thread powerup_timeout(); + powerup thread powerup_wobble(); + powerup thread powerup_grab(); + powerup thread powerup_move(); + powerup thread powerup_emp(); + level.zombie_vars[ "zombie_drop_item" ] = 0; + level notify( "powerup_dropped" ); +} + +specific_powerup_drop( powerup_name, drop_spot, powerup_team, powerup_location ) //checked partially changed to match cerberus output +{ + powerup = maps/mp/zombies/_zm_net::network_safe_spawn( "powerup", 1, "script_model", drop_spot + vectorScale( ( 0, 0, 1 ), 40 ) ); + level notify( "powerup_dropped" ); + if ( isDefined( powerup ) ) + { + powerup powerup_setup( powerup_name, powerup_team, powerup_location ); + powerup thread powerup_timeout(); + powerup thread powerup_wobble(); + powerup thread powerup_grab( powerup_team ); + powerup thread powerup_move(); + powerup thread powerup_emp(); + return powerup; + } +} + +quantum_bomb_random_powerup_result( position ) //changed to match cerberus output +{ + if ( !isDefined( level.zombie_include_powerups ) || !level.zombie_include_powerups.size ) + { + return; + } + keys = getarraykeys( level.zombie_include_powerups ); + while ( keys.size ) + { + index = randomint( keys.size ); + if ( !level.zombie_powerups[ keys[ index ] ].zombie_grabbable ) + { + skip = 0; + switch( keys[ index ] ) + { + case "bonus_points_player": + case "bonus_points_team": + case "random_weapon": + skip = 1; + break; + case "fire_sale": + case "full_ammo": + case "insta_kill": + case "minigun": + if ( randomint( 4 ) ) + { + skip = 1; + } + break; + case "bonfire_sale": + case "free_perk": + case "tesla": + if ( randomint( 20 ) ) + { + skip = 1; + } + break; + default: + } + if ( skip ) + { + arrayremovevalue( keys, keys[ index ] ); + continue; + } + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "kill", "quant_good" ); + [[ level.quantum_bomb_play_player_effect_at_position_func ]]( position ); + level specific_powerup_drop( keys[ index ], position ); + return; + } + else + { + arrayremovevalue( keys, keys[ index ] ); + } + } +} + +quantum_bomb_random_zombie_grab_powerup_result( position ) //changed to match cerberus output +{ + if ( !isDefined( level.zombie_include_powerups ) || !level.zombie_include_powerups.size ) + { + return; + } + keys = getarraykeys( level.zombie_include_powerups ); + while ( keys.size ) + { + index = randomint( keys.size ); + if ( level.zombie_powerups[ keys[ index ] ].zombie_grabbable ) + { + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "kill", "quant_bad" ); + [[ level.quantum_bomb_play_player_effect_at_position_func ]]( position ); + level specific_powerup_drop( keys[ index ], position ); + return; + } + else + { + arrayremovevalue( keys, keys[ index ] ); + } + } +} + +quantum_bomb_random_weapon_powerup_result( position ) //checked matches cerberus output +{ + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "kill", "quant_good" ); + [[ level.quantum_bomb_play_player_effect_at_position_func ]]( position ); + level specific_powerup_drop( "random_weapon", position ); +} + +quantum_bomb_random_bonus_or_lose_points_powerup_result( position ) //checked matches cerberus output +{ + rand = randomint( 10 ); + powerup = "bonus_points_team"; + switch( rand ) + { + case 0: + case 1: + powerup = "lose_points_team"; + if ( isDefined( level.zombie_include_powerups[ powerup ] ) ) + { + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "kill", "quant_bad" ); + break; + } + case 2: + case 3: + case 4: + powerup = "bonus_points_player"; + if ( isDefined( level.zombie_include_powerups[ powerup ] ) ) + { + break; + } + default: + powerup = "bonus_points_team"; + break; + } + [[ level.quantum_bomb_play_player_effect_at_position_func ]]( position ); + level specific_powerup_drop( powerup, position ); +} + +special_powerup_drop( drop_point ) //checked changed to match cerberus output +{ + if ( !isDefined( level.zombie_include_powerups ) || level.zombie_include_powerups.size == 0 ) + { + return; + } + powerup = spawn( "script_model", drop_point + vectorScale( ( 0, 0, 1 ), 40 ) ); + playable_area = getentarray( "player_volume", "script_noteworthy" ); + valid_drop = 0; + for ( i = 0; i < playable_area.size; i++ ) + { + if ( powerup istouching( playable_area[ i ] ) ) + { + valid_drop = 1; + break; + } + } + if ( !valid_drop ) + { + powerup delete(); + return; + } + powerup special_drop_setup(); +} + +cleanup_random_weapon_list() //checked matches cerberus output +{ + self waittill( "death" ); + arrayremovevalue( level.random_weapon_powerups, self ); +} + +powerup_setup( powerup_override, powerup_team, powerup_location ) //checked partially changed to match cerberus output +{ + powerup = undefined; + if ( !isDefined( powerup_override ) ) + { + powerup = get_valid_powerup(); + } + else + { + powerup = powerup_override; + if ( powerup == "tesla" && tesla_powerup_active() ) + { + powerup = "minigun"; + } + } + struct = level.zombie_powerups[ powerup ]; + if ( powerup == "random_weapon" ) + { + players = get_players(); + self.weapon = maps/mp/zombies/_zm_magicbox::treasure_chest_chooseweightedrandomweapon( players[ 0 ] ); + self.base_weapon = self.weapon; + if ( !isDefined( level.random_weapon_powerups ) ) + { + level.random_weapon_powerups = []; + } + level.random_weapon_powerups[ level.random_weapon_powerups.size ] = self; + self thread cleanup_random_weapon_list(); + if ( isDefined( level.zombie_weapons[ self.weapon ].upgrade_name ) && !randomint( 4 ) ) + { + self.weapon = level.zombie_weapons[ self.weapon ].upgrade_name; + } + self setmodel( getweaponmodel( self.weapon ) ); + self useweaponhidetags( self.weapon ); + offsetdw = vectorScale( ( 1, 1, 1 ), 3 ); + self.worldgundw = undefined; + if ( maps/mp/zombies/_zm_magicbox::weapon_is_dual_wield( self.weapon ) ) + { + self.worldgundw = spawn( "script_model", self.origin + offsetdw ); + self.worldgundw.angles = self.angles; + self.worldgundw setmodel( maps/mp/zombies/_zm_magicbox::get_left_hand_weapon_model_name( self.weapon ) ); + self.worldgundw useweaponhidetags( self.weapon ); + self.worldgundw linkto( self, "tag_weapon", offsetdw, ( 0, 0, 0 ) ); + } + } + else + { + self setmodel( struct.model_name ); + } + maps/mp/_demo::bookmark( "zm_powerup_dropped", getTime(), undefined, undefined, 1 ); + playsoundatposition( "zmb_spawn_powerup", self.origin ); + if ( isDefined( powerup_team ) ) + { + self.powerup_team = powerup_team; + } + if ( isDefined( powerup_location ) ) + { + self.powerup_location = powerup_location; + } + self.powerup_name = struct.powerup_name; + self.hint = struct.hint; + self.solo = struct.solo; + self.caution = struct.caution; + self.zombie_grabbable = struct.zombie_grabbable; + self.func_should_drop_with_regular_powerups = struct.func_should_drop_with_regular_powerups; + if ( isDefined( struct.fx ) ) + { + self.fx = struct.fx; + } + if ( isDefined( struct.can_pick_up_in_last_stand ) ) + { + self.can_pick_up_in_last_stand = struct.can_pick_up_in_last_stand; + } + self playloopsound( "zmb_spawn_powerup_loop" ); + level.active_powerups[ level.active_powerups.size ] = self; +} + +special_drop_setup() //checked matches cerberus output +{ + powerup = undefined; + is_powerup = 1; + if ( level.round_number <= 10 ) + { + powerup = get_valid_powerup(); + } + else + { + powerup = level.zombie_special_drop_array[ randomint( level.zombie_special_drop_array.size ) ]; + if ( level.round_number > 15 && randomint( 100 ) < ( ( level.round_number - 15 ) * 5 ) ) + { + powerup = "nothing"; + } + } + switch( powerup ) + { + case "all_revive": + case "bonfire_sale": + case "bonus_points_player": + case "bonus_points_team": + case "carpenter": + case "double_points": + case "empty_clip": + case "fire_sale": + case "free_perk": + case "insta_kill": + case "lose_perk": + case "lose_points_team": + case "minigun": + case "nuke": + case "random_weapon": + case "tesla": + case "zombie_blood": + break; + case "full_ammo": + if ( level.round_number > 10 && randomint( 100 ) < ( ( level.round_number - 10 ) * 5 ) ) + { + powerup = level.zombie_powerup_array[ randomint( level.zombie_powerup_array.size ) ]; + } + break; + case "dog": + if ( level.round_number >= 15 ) + { + is_powerup = 0; + dog_spawners = getentarray( "special_dog_spawner", "targetname" ); + thread play_sound_2d( "sam_nospawn" ); + } + else + { + powerup = get_valid_powerup(); + } + break; + default: + if ( isDefined( level._zombiemode_special_drop_setup ) ) + { + is_powerup = [[ level._zombiemode_special_drop_setup ]]( powerup ); + } + else + { + is_powerup = 0; + playfx( level._effect[ "lightning_dog_spawn" ], self.origin ); + playsoundatposition( "pre_spawn", self.origin ); + wait 1.5; + playsoundatposition( "zmb_bolt", self.origin ); + earthquake( 0.5, 0.75, self.origin, 1000 ); + playrumbleonposition( "explosion_generic", self.origin ); + playsoundatposition( "spawn", self.origin ); + wait 1; + thread play_sound_2d( "sam_nospawn" ); + self delete(); + } + } + if ( is_powerup ) + { + playfx( level._effect[ "lightning_dog_spawn" ], self.origin ); + playsoundatposition( "pre_spawn", self.origin ); + wait 1.5; + playsoundatposition( "zmb_bolt", self.origin ); + earthquake( 0.5, 0.75, self.origin, 1000 ); + playrumbleonposition( "explosion_generic", self.origin ); + playsoundatposition( "spawn", self.origin ); + self powerup_setup( powerup ); + self thread powerup_timeout(); + self thread powerup_wobble(); + self thread powerup_grab(); + self thread powerup_move(); + self thread powerup_emp(); + } +} + +powerup_zombie_grab_trigger_cleanup( trigger ) //checked matches cerberus output +{ + self waittill_any( "powerup_timedout", "powerup_grabbed", "hacked" ); + trigger delete(); +} + +powerup_zombie_grab( powerup_team ) //checked changed to match cerberus output +{ + self endon( "powerup_timedout" ); + self endon( "powerup_grabbed" ); + self endon( "hacked" ); + zombie_grab_trigger = spawn( "trigger_radius", self.origin - vectorScale( ( 0, 0, 1 ), 40 ), 4, 32, 72 ); + zombie_grab_trigger enablelinkto(); + zombie_grab_trigger linkto( self ); + zombie_grab_trigger setteamfortrigger( level.zombie_team ); + self thread powerup_zombie_grab_trigger_cleanup( zombie_grab_trigger ); + poi_dist = 300; + if ( isDefined( level._zombie_grabbable_poi_distance_override ) ) + { + poi_dist = level._zombie_grabbable_poi_distance_override; + } + zombie_grab_trigger create_zombie_point_of_interest( poi_dist, 2, 0, 1, undefined, undefined, powerup_team ); + while ( isDefined( self ) ) + { + zombie_grab_trigger waittill( "trigger", who ); + if ( isDefined( level._powerup_grab_check ) ) + { + if ( !self [[ level._powerup_grab_check ]]( who ) ) + { + continue; + } + } + else if ( !isDefined( who ) || !isai( who ) ) + { + continue; + } + playfx( level._effect[ "powerup_grabbed_red" ], self.origin ); + playfx( level._effect[ "powerup_grabbed_wave_red" ], self.origin ); + switch( self.powerup_name ) + { + case "lose_points_team": + level thread lose_points_team_powerup( self ); + players = get_players(); + players[ randomintrange( 0, players.size ) ] thread powerup_vo( "lose_points" ); + break; + case "lose_perk": + level thread lose_perk_powerup( self ); + break; + case "empty_clip": + level thread empty_clip_powerup( self ); + break; + default: + if ( isDefined( level._zombiemode_powerup_zombie_grab ) ) + { + level thread [[ level._zombiemode_powerup_zombie_grab ]]( self ); + } + if ( isDefined( level._game_mode_powerup_zombie_grab ) ) + { + level thread [[ level._game_mode_powerup_zombie_grab ]]( self, who ); + } + break; + } + level thread maps/mp/zombies/_zm_audio::do_announcer_playvox( "powerup", self.powerup_name ); + wait 0.1; + playsoundatposition( "zmb_powerup_grabbed", self.origin ); + self stoploopsound(); + self powerup_delete(); + self notify( "powerup_grabbed" ); + } +} + +powerup_grab(powerup_team) //checked partially changed to match cerberus output +{ + if ( isdefined( self ) && self.zombie_grabbable ) + { + self thread powerup_zombie_grab( powerup_team ); + return; + } + + self endon ( "powerup_timedout" ); + self endon ( "powerup_grabbed" ); + + range_squared = 4096; + while ( isdefined( self ) ) + { + players = get_players(); + i = 0; + while ( i < players.size ) + { + // Don't let them grab the minigun, tesla, or random weapon if they're downed or reviving + // due to weapon switching issues. + if ( ( self.powerup_name == "minigun" || self.powerup_name == "tesla" ) && players[ i ] maps/mp/zombies/_zm_laststand::player_is_in_laststand() || players[ i ] maps/mp/zombies/_zm_laststand::player_is_in_laststand() && ( self.powerup_name == "random_weapon" || self.powerup_name == "meat_stink" ) || players[ i ] usebuttonpressed() && players[ i ] in_revive_trigger() ) + { + i++; + continue; + } + if ( !is_true( self.can_pick_up_in_last_stand ) && players[ i ] maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + i++; + continue; + } + ignore_range = 0; + if ( isdefined( players[ i ].ignore_range_powerup ) && players[ i ].ignore_range_powerup == self ) + { + players[ i ].ignore_range_powerup = undefined; + ignore_range = 1; + } + if ( DistanceSquared( players[ i ].origin, self.origin ) < range_squared || ignore_range ) + { + if ( isdefined(level._powerup_grab_check ) ) + { + if ( !self [[ level._powerup_grab_check ]]( players[ i ] ) ) + { + i++; + continue; + } + } + else if ( isdefined( level.zombie_powerup_grab_func ) ) + { + level thread [[ level.zombie_powerup_grab_func ]](); + break; + } + switch ( self.powerup_name ) + { + case "nuke": + level thread nuke_powerup( self, players[ i ].team ); + players[ i ] thread powerup_vo( "nuke" ); + zombies = getaiarray( level.zombie_team ); + players[ i ].zombie_nuked = arraysort( zombies, self.origin ); + players[ i ] notify( "nuke_triggered" ); + break; + case "full_ammo": + level thread full_ammo_powerup( self ,players[ i ] ); + players[ i ] thread powerup_vo( "full_ammo" ); + break; + case "double_points": + level thread double_points_powerup( self, players[ i ] ); + players[ i ] thread powerup_vo( "double_points" ); + break; + case "insta_kill": + level thread insta_kill_powerup( self,players[ i ] ); + players[ i ] thread powerup_vo( "insta_kill" ); + break; + case "carpenter": + if ( is_classic() ) + { + players[ i ] thread maps/mp/zombies/_zm_pers_upgrades::persistent_carpenter_ability_check(); + } + if ( isdefined( level.use_new_carpenter_func ) ) + { + level thread [[ level.use_new_carpenter_func ]]( self.origin ); + } + else + { + level thread start_carpenter( self.origin ); + } + players[ i ] thread powerup_vo( "carpenter" ); + break; + case "fire_sale": + level thread start_fire_sale( self ); + players[ i ] thread powerup_vo( "firesale" ); + break; + case "bonfire_sale": + level thread start_bonfire_sale( self ); + players[ i ] thread powerup_vo( "firesale" ); + break; + case "minigun": + level thread minigun_weapon_powerup( players[ i ] ); + players[ i ] thread powerup_vo( "minigun" ); + break; + case "free_perk": + level thread free_perk_powerup( self ); + break; + case "tesla": + level thread tesla_weapon_powerup( players[ i ] ); + players[ i ] thread powerup_vo( "tesla" ); + break; + case "random_weapon": + if ( !level random_weapon_powerup( self, players[ i ] ) ) + { + i++; + continue; + } + break; + case "bonus_points_player": + level thread bonus_points_player_powerup( self, players[ i ] ); + players[ i ] thread powerup_vo( "bonus_points_solo" ); + break; + case "bonus_points_team": + level thread bonus_points_team_powerup( self ); + players[ i ] thread powerup_vo( "bonus_points_team" ); + break; + case "teller_withdrawl": + level thread teller_withdrawl( self ,players[ i ] ); + break; + default: + if ( IsDefined( level._zombiemode_powerup_grab ) ) + { + level thread [[ level._zombiemode_powerup_grab ]]( self, players[ i ] ); + } + break; + } + + maps\mp\_demo::bookmark( "zm_player_powerup_grabbed", gettime(), players[ i ] ); + + if( should_award_stat ( self.powerup_name )) //don't do this for things that aren't really a powerup + { + //track # of picked up powerups/drops for the player + players[i] maps/mp/zombies/_zm_stats::increment_client_stat( "drops" ); + players[i] maps/mp/zombies/_zm_stats::increment_player_stat( "drops" ); + players[i] maps/mp/zombies/_zm_stats::increment_client_stat( self.powerup_name + "_pickedup" ); + players[i] maps/mp/zombies/_zm_stats::increment_player_stat( self.powerup_name + "_pickedup" ); + } + + if ( self.solo ) + { + playfx( level._effect[ "powerup_grabbed_solo" ], self.origin ); + playfx( level._effect[ "powerup_grabbed_wave_solo" ], self.origin ); + } + else if ( self.caution ) + { + playfx( level._effect[ "powerup_grabbed_caution" ], self.origin ); + playfx( level._effect[ "powerup_grabbed_wave_caution" ], self.origin ); + } + else + { + playfx( level._effect[ "powerup_grabbed" ], self.origin ); + playfx( level._effect[ "powerup_grabbed_wave" ], self.origin ); + } + + if ( is_true( self.stolen ) ) + { + level notify( "monkey_see_monkey_dont_achieved" ); + } + if ( isdefined( self.grabbed_level_notify ) ) + { + level notify( self.grabbed_level_notify ); + } + + // RAVEN BEGIN bhackbarth: since there is a wait here, flag the powerup as being taken + self.claimed = true; + self.power_up_grab_player = players[ i ]; //Player who grabbed the power up + // RAVEN END + + wait 0.1 ; + + playsoundatposition("zmb_powerup_grabbed", self.origin); + self stoploopsound(); + self hide(); + + //Preventing the line from playing AGAIN if fire sale becomes active before it runs out + if ( self.powerup_name != "fire_sale" ) + { + if ( isdefined( self.power_up_grab_player ) ) + { + if ( isdefined( level.powerup_intro_vox ) ) + { + level thread [[ level.powerup_intro_vox ]]( self ); + return; + } + else if ( isdefined( level.powerup_vo_available ) ) + { + can_say_vo = [[ level.powerup_vo_available ]](); + if ( !can_say_vo ) + { + self powerup_delete(); + self notify( "powerup_grabbed" ); + return; + } + } + } + } + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( self.powerup_name, self.power_up_grab_player.pers[ "team" ] ); + self powerup_delete(); + self notify( "powerup_grabbed" ); + } + i++; + } + wait 0.1; + } +} + + +start_fire_sale( item ) //checked matches cerberus output +{ + if ( level.zombie_vars[ "zombie_powerup_fire_sale_time" ] > 0 && is_true( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] ) ) + { + level.zombie_vars[ "zombie_powerup_fire_sale_time" ] += 30; + return; + } + level notify( "powerup fire sale" ); + level endon( "powerup fire sale" ); + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "fire_sale" ); + level.zombie_vars[ "zombie_powerup_fire_sale_on" ] = 1; + level thread toggle_fire_sale_on(); + level.zombie_vars[ "zombie_powerup_fire_sale_time" ] = 30; + while ( level.zombie_vars[ "zombie_powerup_fire_sale_time" ] > 0 ) + { + wait 0.05; + level.zombie_vars[ "zombie_powerup_fire_sale_time" ] -= 0.05; + } + level.zombie_vars[ "zombie_powerup_fire_sale_on" ] = 0; + level notify( "fire_sale_off" ); +} + +start_bonfire_sale( item ) //checked matches cerberus output +{ + level notify( "powerup bonfire sale" ); + level endon( "powerup bonfire sale" ); + temp_ent = spawn( "script_origin", ( 0, 0, 0 ) ); + temp_ent playloopsound( "zmb_double_point_loop" ); + level.zombie_vars[ "zombie_powerup_bonfire_sale_on" ] = 1; + level thread toggle_bonfire_sale_on(); + level.zombie_vars[ "zombie_powerup_bonfire_sale_time" ] = 30; + while ( level.zombie_vars[ "zombie_powerup_bonfire_sale_time" ] > 0 ) + { + wait 0.05; + level.zombie_vars[ "zombie_powerup_bonfire_sale_time" ] -= 0.05; + } + level.zombie_vars[ "zombie_powerup_bonfire_sale_on" ] = 0; + level notify( "bonfire_sale_off" ); + players = get_players(); + i = 0; + while ( i < players.size ) + { + players[ i ] playsound( "zmb_points_loop_off" ); + i++; + } + temp_ent delete(); +} + +start_carpenter( origin ) //checked partially changed to match cerberus output +{ + window_boards = getstructarray( "exterior_goal", "targetname" ); + total = level.exterior_goals.size; + carp_ent = spawn( "script_origin", ( 0, 0, 0 ) ); + carp_ent playloopsound( "evt_carpenter" ); + while ( 1 ) + { + windows = get_closest_window_repair( window_boards, origin ); + if ( !isDefined( windows ) ) + { + carp_ent stoploopsound( 1 ); + carp_ent playsoundwithnotify( "evt_carpenter_end", "sound_done" ); + carp_ent waittill( "sound_done" ); + break; + } + else arrayremovevalue( window_boards, windows ); + while ( 1 ) + { + if ( all_chunks_intact( windows, windows.barrier_chunks ) ) + { + break; + } + else chunk = get_random_destroyed_chunk( windows, windows.barrier_chunks ); + if ( !isDefined( chunk ) ) + { + break; + } + windows thread maps/mp/zombies/_zm_blockers::replace_chunk( windows, chunk, undefined, maps/mp/zombies/_zm_powerups::is_carpenter_boards_upgraded(), 1 ); + if ( isDefined( windows.clip ) ) + { + windows.clip enable_trigger(); + windows.clip disconnectpaths(); + } + else + { + blocker_disconnect_paths( windows.neg_start, windows.neg_end ); + } + wait_network_frame(); + wait 0.05; + } + wait_network_frame(); + } + players = get_players(); + i = 0; + while ( i < players.size ) + { + players[ i ] maps/mp/zombies/_zm_score::player_add_points( "carpenter_powerup", 200 ); + i++; + } + carp_ent delete(); +} + +get_closest_window_repair( windows, origin ) //checked partially changed to match cerberus output +{ + current_window = undefined; + shortest_distance = undefined; + i = 0; + while ( i < windows.size ) + { + if ( all_chunks_intact( windows, windows[ i ].barrier_chunks ) ) + { + i++; + continue; + } + if ( !isDefined( current_window ) ) + { + current_window = windows[ i ]; + shortest_distance = distancesquared( current_window.origin, origin ); + i++; + continue; + } + if ( distancesquared( windows[ i ].origin, origin ) < shortest_distance ) + { + current_window = windows[ i ]; + shortest_distance = distancesquared( windows[ i ].origin, origin ); + } + i++; + } + return current_window; +} + +powerup_vo( type ) //checked matches cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( isDefined( level.powerup_vo_available ) ) + { + if ( ![[ level.powerup_vo_available ]]() ) + { + return; + } + } + wait randomfloatrange( 2, 2.5 ); + if ( type == "tesla" ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", type ); + } + else + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "powerup", type ); + } + if ( isDefined( level.custom_powerup_vo_response ) ) + { + level [[ level.custom_powerup_vo_response ]]( self, type ); + } +} + +powerup_wobble_fx() //checked matches cerberus output +{ + self endon( "death" ); + if ( !isDefined( self ) ) + { + return; + } + if ( isDefined( level.powerup_fx_func ) ) + { + self thread [[ level.powerup_fx_func ]](); + return; + } + if ( self.solo ) + { + self setclientfield( "powerup_fx", 2 ); + } + else if ( self.caution ) + { + self setclientfield( "powerup_fx", 4 ); + } + else if ( self.zombie_grabbable ) + { + self setclientfield( "powerup_fx", 3 ); + } + else + { + self setclientfield( "powerup_fx", 1 ); + } +} + +powerup_wobble() //checked matches cerberus output +{ + self endon( "powerup_grabbed" ); + self endon( "powerup_timedout" ); + self thread powerup_wobble_fx(); + while ( isDefined( self ) ) + { + waittime = randomfloatrange( 2.5, 5 ); + yaw = randomint( 360 ); + if ( yaw > 300 ) + { + yaw = 300; + } + else + { + if ( yaw < 60 ) + { + yaw = 60; + } + } + yaw = self.angles[ 1 ] + yaw; + new_angles = ( -60 + randomint( 120 ), yaw, -45 + randomint( 90 ) ); + self rotateto( new_angles, waittime, waittime * 0.5, waittime * 0.5 ); + if ( isDefined( self.worldgundw ) ) + { + self.worldgundw rotateto( new_angles, waittime, waittime * 0.5, waittime * 0.5 ); + } + wait randomfloat( waittime - 0.1 ); + } +} + +powerup_timeout() //checked partially changed to match cerberus output +{ + if ( isDefined( level._powerup_timeout_override ) && !isDefined( self.powerup_team ) ) + { + self thread [[ level._powerup_timeout_override ]](); + return; + } + self endon( "powerup_grabbed" ); + self endon( "death" ); + self endon( "powerup_reset" ); + self show(); + wait_time = 15; + if ( isDefined( level._powerup_timeout_custom_time ) ) + { + time = [[ level._powerup_timeout_custom_time ]]( self ); + if ( time == 0 ) + { + return; + } + wait_time = time; + } + wait wait_time; + i = 0; + while ( i < 40 ) + { + if ( i % 2 ) + { + self ghost(); + if ( isDefined( self.worldgundw ) ) + { + self.worldgundw ghost(); + } + } + else + { + self show(); + if ( isDefined( self.worldgundw ) ) + { + self.worldgundw show(); + } + } + if ( i < 15 ) + { + wait 0.5; + i++; + continue; + } + else if ( i < 25 ) + { + wait 0.25; + i++; + continue; + } + wait 0.1; + i++; + } + self notify( "powerup_timedout" ); + self powerup_delete(); +} + +powerup_delete() //checked matches cerberus output +{ + arrayremovevalue( level.active_powerups, self, 0 ); + if ( isDefined( self.worldgundw ) ) + { + self.worldgundw delete(); + } + self delete(); +} + +powerup_delete_delayed( time ) //checked matches cerberus output +{ + if ( isDefined( time ) ) + { + wait time; + } + else + { + wait 0.01; + } + self powerup_delete(); +} + +nuke_powerup( drop_item, player_team ) //checked changed to match cerberus output +{ + location = drop_item.origin; + playfx( drop_item.fx, location ); + level thread nuke_flash( player_team ); + wait 0.5; + zombies = getaiarray( level.zombie_team ); + zombies = arraysort( zombies, location ); + zombies_nuked = []; + i = 0; + while ( i < zombies.size ) + { + if ( is_true( zombies[ i ].ignore_nuke ) ) + { + i++; + continue; + } + if ( is_true( zombies[ i ].marked_for_death ) ) + { + i++; + continue; + } + if ( isdefined( zombies[ i ].nuke_damage_func ) ) + { + zombies[ i ] thread [[ zombies[ i ].nuke_damage_func ]](); + i++; + continue; + } + if ( is_magic_bullet_shield_enabled( zombies[ i ] ) ) + { + i++; + continue; + } + zombies[ i ].marked_for_death = 1; + //imported from bo3 _zm_powerup_nuke.gsc + if ( !zombies[ i ].nuked && !is_magic_bullet_shield_enabled( zombies[ i ] ) ) + { + zombies[ i ].nuked = 1; + zombies_nuked[ zombies_nuked.size ] = zombies[ i ]; + } + i++; + } + i = 0; + while ( i < zombies_nuked.size ) + { + wait randomfloatrange( 0.1, 0.7 ); + if ( !isdefined( zombies_nuked[ i ] ) ) + { + i++; + continue; + } + if ( is_magic_bullet_shield_enabled( zombies_nuked[ i ] ) ) + { + i++; + continue; + } + if ( i < 5 && !zombies_nuked[ i ].isdog ) + { + zombies_nuked[ i ] thread maps/mp/animscripts/zm_death::flame_death_fx(); + } + if ( !zombies_nuked[ i ].isdog ) + { + if ( !is_true( zombies_nuked[ i ].no_gib ) ) + { + zombies_nuked[ i ] maps/mp/zombies/_zm_spawner::zombie_head_gib(); + } + zombies_nuked[ i ] playsound("evt_nuked"); + } + zombies_nuked[ i ] dodamage(zombies_nuked[i].health + 666, zombies_nuked[ i ].origin ); + i++; + } + players = get_players( player_team ); + for ( i = 0; i < players.size; i++ ) + { + players[ i ] maps/mp/zombies/_zm_score::player_add_points( "nuke_powerup", 400 ); + } +} + +nuke_flash( team ) //checked matches cerberus output +{ + if ( isDefined( team ) ) + { + get_players()[ 0 ] playsoundtoteam( "evt_nuke_flash", team ); + } + else + { + get_players()[ 0 ] playsound( "evt_nuke_flash" ); + } + fadetowhite = newhudelem(); + fadetowhite.x = 0; + fadetowhite.y = 0; + fadetowhite.alpha = 0; + fadetowhite.horzalign = "fullscreen"; + fadetowhite.vertalign = "fullscreen"; + fadetowhite.foreground = 1; + fadetowhite setshader( "white", 640, 480 ); + fadetowhite fadeovertime( 0.2 ); + fadetowhite.alpha = 0.8; + wait 0.5; + fadetowhite fadeovertime( 1 ); + fadetowhite.alpha = 0; + wait 1.1; + fadetowhite destroy(); +} + +double_points_powerup( drop_item, player ) //checked partially matches cerberus output did not change +{ + level notify( "powerup points scaled_" + player.team ); + level endon( "powerup points scaled_" + player.team ); + team = player.team; + level thread point_doubler_on_hud( drop_item, team ); + if ( is_true( level.pers_upgrade_double_points ) ) + { + player thread maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_double_points_pickup_start(); + } + if ( isDefined( level.current_game_module ) && level.current_game_module == 2 ) + { + if ( isDefined( player._race_team ) ) + { + if ( player._race_team == 1 ) + { + level._race_team_double_points = 1; + } + else + { + level._race_team_double_points = 2; + } + } + } + level.zombie_vars[ team ][ "zombie_point_scalar" ] = 2; + players = get_players(); + for ( player_index = 0; player_index < players.size; player_index++ ) + { + if ( team == players[ player_index ].team ) + { + players[ player_index ] setclientfield( "score_cf_double_points_active", 1 ); + } + } + wait 30; + level.zombie_vars[ team ][ "zombie_point_scalar" ] = 1; + level._race_team_double_points = undefined; + players = get_players(); + for ( player_index = 0; player_index < players.size; player_index++ ) + { + if ( team == players[ player_index ].team ) + { + players[ player_index ] setclientfield( "score_cf_double_points_active", 0 ); + } + } +} + +full_ammo_powerup( drop_item, player ) //checked changed to match cerberus output +{ + players = get_players( player.team ); + if ( isdefined( level._get_game_module_players ) ) + { + players = [[ level._get_game_module_players ]]( player ); + } + i = 0; + while ( i < players.size ) + { + if ( players[ i ] maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + i++; + continue; + } + primary_weapons = players[ i ] getweaponslist( 1 ); + players[ i ] notify( "zmb_max_ammo" ); + players[ i ] notify( "zmb_lost_knife" ); + players[ i ] notify( "zmb_disable_claymore_prompt" ); + players[ i ] notify( "zmb_disable_spikemore_prompt" ); + x = 0; + while ( x < primary_weapons.size ) + { + if ( level.headshots_only && is_lethal_grenade(primary_weapons[ x ] ) ) + { + x++; + continue; + } + if ( isdefined( level.zombie_include_equipment ) && isdefined( level.zombie_include_equipment[ primary_weapons[ x ] ] ) ) + { + x++; + continue; + } + if ( isdefined( level.zombie_weapons_no_max_ammo ) && isdefined( level.zombie_weapons_no_max_ammo[ primary_weapons[ x ] ] ) ) + { + x++; + continue; + } + if ( players[ i ] hasweapon( primary_weapons[ x ] ) ) + { + players[ i ] givemaxammo( primary_weapons[ x ] ); + } + x++; + } + i++; + } + level thread full_ammo_on_hud( drop_item, player.team ); +} + +insta_kill_powerup( drop_item, player ) //checked matches cerberus output +{ + level notify( "powerup instakill_" + player.team ); + level endon( "powerup instakill_" + player.team ); + if ( isDefined( level.insta_kill_powerup_override ) ) + { + level thread [[ level.insta_kill_powerup_override ]]( drop_item, player ); + return; + } + if ( is_classic() ) + { + player thread maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_insta_kill_upgrade_check(); + } + team = player.team; + level thread insta_kill_on_hud( drop_item, team ); + level.zombie_vars[ team ][ "zombie_insta_kill" ] = 1; + wait 30; + level.zombie_vars[ team ][ "zombie_insta_kill" ] = 0; + players = get_players( team ); + i = 0; + while ( i < players.size ) + { + if ( isDefined( players[ i ] ) ) + { + players[ i ] notify( "insta_kill_over" ); + } + i++; + } +} + +is_insta_kill_active() //checked matches cerberus output +{ + return level.zombie_vars[ self.team ][ "zombie_insta_kill" ]; +} + +check_for_instakill( player, mod, hit_location ) //checked changed to match cerberus output +{ + if ( isDefined( player ) && isalive( player ) && isDefined( level.check_for_instakill_override ) ) + { + if ( !self [[ level.check_for_instakill_override ]]( player ) ) + { + return; + } + if ( player.use_weapon_type == "MOD_MELEE" ) + { + player.last_kill_method = "MOD_MELEE"; + } + else + { + player.last_kill_method = "MOD_UNKNOWN"; + } + modname = remove_mod_from_methodofdeath( mod ); + if ( isDefined( self.no_gib ) && self.no_gib ) + { + self maps/mp/zombies/_zm_spawner::zombie_head_gib(); + } + self.health = 1; + self dodamage( self.health + 666, self.origin, player, self, hit_location, modname ); + player notify( "zombie_killed" ); + } + if ( isDefined( player ) && isalive( player ) && level.zombie_vars[ player.team ][ "zombie_insta_kill" ] || is_true( player.personal_instakill ) ) + { + if ( is_magic_bullet_shield_enabled( self ) ) + { + return; + } + if ( isDefined( self.instakill_func ) ) + { + self thread [[ self.instakill_func ]](); + return; + } + if ( player.use_weapon_type == "MOD_MELEE" ) + { + player.last_kill_method = "MOD_MELEE"; + } + else + { + player.last_kill_method = "MOD_UNKNOWN"; + } + modname = remove_mod_from_methodofdeath( mod ); + if ( flag( "dog_round" ) ) + { + self.health = 1; + self dodamage( self.health + 666, self.origin, player, self, hit_location, modname ); + player notify( "zombie_killed" ); + } + else if ( isdefined( self.no_gib ) && !self.no_gib ) + { + self maps/mp/zombies/_zm_spawner::zombie_head_gib(); + } + self.health = 1; + self dodamage( self.health + 666, self.origin, player, self, hit_location, modname ); + player notify( "zombie_killed" ); + } +} + +insta_kill_on_hud( drop_item, player_team ) //checked matches cerberus output +{ + if ( level.zombie_vars[ player_team ][ "zombie_powerup_insta_kill_on" ] ) + { + level.zombie_vars[ player_team ][ "zombie_powerup_insta_kill_time" ] = 30; + return; + } + level.zombie_vars[ player_team ][ "zombie_powerup_insta_kill_on" ] = 1; + level thread time_remaning_on_insta_kill_powerup( player_team ); +} + +time_remaning_on_insta_kill_powerup( player_team ) //checked matches cerberus output +{ + temp_enta = spawn( "script_origin", ( 0, 0, 0 ) ); + temp_enta playloopsound( "zmb_insta_kill_loop" ); + while ( level.zombie_vars[ player_team ][ "zombie_powerup_insta_kill_time" ] >= 0 ) + { + wait 0.05; + level.zombie_vars[ player_team ][ "zombie_powerup_insta_kill_time" ] -= 0.05; + } + get_players()[ 0 ] playsoundtoteam( "zmb_insta_kill", player_team ); + temp_enta stoploopsound( 2 ); + level.zombie_vars[ player_team ][ "zombie_powerup_insta_kill_on" ] = 0; + level.zombie_vars[ player_team ][ "zombie_powerup_insta_kill_time" ] = 30; + temp_enta delete(); +} + +point_doubler_on_hud( drop_item, player_team ) //checked matches cerberus output +{ + self endon( "disconnect" ); + if ( level.zombie_vars[ player_team ][ "zombie_powerup_point_doubler_on" ] ) + { + level.zombie_vars[ player_team ][ "zombie_powerup_point_doubler_time" ] = 30; + return; + } + level.zombie_vars[ player_team ][ "zombie_powerup_point_doubler_on" ] = 1; + level thread time_remaining_on_point_doubler_powerup( player_team ); +} + +time_remaining_on_point_doubler_powerup( player_team ) //checked partially matches cerberus output did not change +{ + temp_ent = spawn( "script_origin", ( 0, 0, 0 ) ); + temp_ent playloopsound( "zmb_double_point_loop" ); + while ( level.zombie_vars[ player_team ][ "zombie_powerup_point_doubler_time" ] >= 0 ) + { + wait 0.05; + level.zombie_vars[ player_team ][ "zombie_powerup_point_doubler_time" ] -= 0.05; + } + level.zombie_vars[ player_team ][ "zombie_powerup_point_doubler_on" ] = 0; + players = get_players( player_team ); + for ( i = 0; i < players.size; i++ ) + { + players[ i ] playsound( "zmb_points_loop_off" ); + } + temp_ent stoploopsound( 2 ); + level.zombie_vars[ player_team ][ "zombie_powerup_point_doubler_time" ] = 30; + temp_ent delete(); +} + +toggle_bonfire_sale_on() //checked matches cerberus output +{ + level endon( "powerup bonfire sale" ); + if ( !isDefined( level.zombie_vars[ "zombie_powerup_bonfire_sale_on" ] ) ) + { + return; + } + if ( level.zombie_vars[ "zombie_powerup_bonfire_sale_on" ] ) + { + if ( isDefined( level.bonfire_init_func ) ) + { + level thread [[ level.bonfire_init_func ]](); + } + level waittill( "bonfire_sale_off" ); + } +} + +toggle_fire_sale_on() //checked partially matches cerberus output did not change +{ + level endon( "powerup fire sale" ); + if ( !isDefined( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] ) ) + { + return; + } + while ( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] ) + { + for ( i = 0; i < level.chests.size; i++ ) + { + show_firesale_box = level.chests[ i ] [[ level._zombiemode_check_firesale_loc_valid_func ]](); + if ( show_firesale_box ) + { + level.chests[ i ].zombie_cost = 10; + if ( level.chest_index != i ) + { + level.chests[ i ].was_temp = 1; + if ( is_true( level.chests[ i ].hidden ) ) + { + level.chests[ i ] thread maps/mp/zombies/_zm_magicbox::show_chest(); + } + wait_network_frame(); + } + } + } + level waittill( "fire_sale_off" ); + waittillframeend; + for ( i = 0; i < level.chests.size; i++ ) + { + show_firesale_box = level.chests[ i ] [[ level._zombiemode_check_firesale_loc_valid_func ]](); + if ( show_firesale_box ) + { + if ( level.chest_index != i && isDefined( level.chests[ i ].was_temp ) ) + { + level.chests[ i ].was_temp = undefined; + level thread remove_temp_chest( i ); + } + level.chests[ i ].zombie_cost = level.chests[ i ].old_cost; + } + } + } +} + +fire_sale_weapon_wait() //checked matches cerberus output +{ + self.zombie_cost = self.old_cost; + while ( isDefined( self.chest_user ) ) + { + wait_network_frame(); + } + self set_hint_string( self, "default_treasure_chest", self.zombie_cost ); +} + +remove_temp_chest( chest_index ) //checked partially matches cerberus output did not change +{ + while ( isDefined( level.chests[ chest_index ].chest_user ) || isDefined( level.chests[ chest_index ]._box_open ) && level.chests[ chest_index ]._box_open == 1 ) + { + wait_network_frame(); + } + if ( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] ) + { + level.chests[ chest_index ].was_temp = 1; + level.chests[ chest_index ].zombie_cost = 10; + return; + } + for ( i = 0; i < chest_index; i++ ) + { + wait_network_frame(); + } + playfx( level._effect[ "poltergeist" ], level.chests[ chest_index ].orig_origin ); + level.chests[ chest_index ].zbarrier playsound( "zmb_box_poof_land" ); + level.chests[ chest_index ].zbarrier playsound( "zmb_couch_slam" ); + wait_network_frame(); + level.chests[ chest_index ] maps/mp/zombies/_zm_magicbox::hide_chest(); +} + +devil_dialog_delay() //checked matches cerberus output +{ + wait 1; +} + +full_ammo_on_hud( drop_item, player_team ) //checked matches cerberus output +{ + self endon( "disconnect" ); + hudelem = maps/mp/gametypes_zm/_hud_util::createserverfontstring( "objective", 2, player_team ); + hudelem maps/mp/gametypes_zm/_hud_util::setpoint( "TOP", undefined, 0, level.zombie_vars[ "zombie_timer_offset" ] - ( level.zombie_vars[ "zombie_timer_offset_interval" ] * 2 ) ); + hudelem.sort = 0.5; + hudelem.alpha = 0; + hudelem fadeovertime( 0.5 ); + hudelem.alpha = 1; + if ( isDefined( drop_item ) ) + { + hudelem.label = drop_item.hint; + } + hudelem thread full_ammo_move_hud( player_team ); +} + +full_ammo_move_hud( player_team ) //checked matches cerberus output +{ + players = get_players( player_team ); + players[ 0 ] playsoundtoteam( "zmb_full_ammo", player_team ); + wait 0.5; + move_fade_time = 1.5; + self fadeovertime( move_fade_time ); + self moveovertime( move_fade_time ); + self.y = 270; + self.alpha = 0; + wait move_fade_time; + self destroy(); +} + +check_for_rare_drop_override( pos ) //checked matches cerberus output +{ + if ( isDefined( flag( "ape_round" ) ) && flag( "ape_round" ) ) + { + return 0; + } + return 0; +} + +setup_firesale_audio() //checked changed to match cerberus output +{ + wait 2; + intercom = getentarray( "intercom", "targetname" ); + while ( 1 ) + { + while ( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] == 0 ) + { + wait 0.2; + } + for ( i = 0; i < intercom.size; i++ ) + { + intercom [i ] thread play_firesale_audio(); + } + while ( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] == 1 ) + { + wait 0.1; + } + level notify( "firesale_over" ); + } +} + +play_firesale_audio() //checked matches cerberus output +{ + if ( is_true( level.sndfiresalemusoff ) ) + { + return; + } + if ( is_true( level.sndannouncerisrich ) ) + { + self playloopsound( "mus_fire_sale_rich" ); + } + else + { + self playloopsound( "mus_fire_sale" ); + } + level waittill( "firesale_over" ); + self stoploopsound(); +} + +setup_bonfiresale_audio() //checked changed to match cerberus output +{ + wait 2; + intercom = getentarray( "intercom", "targetname" ); + while ( 1 ) + { + while ( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] == 0 ) + { + wait 0.2; + } + for ( i = 0; i < intercom.size; i++ ) + { + intercom[ i ] thread play_bonfiresale_audio(); + } + while ( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] == 1 ) + { + wait 0.1; + } + level notify( "firesale_over" ); + } +} + +play_bonfiresale_audio() //checked matches cerberus output +{ + if ( is_true( level.sndfiresalemusoff ) ) + { + return; + } + if ( is_true( level.sndannouncerisrich ) ) + { + self playloopsound( "mus_fire_sale_rich" ); + } + else + { + self playloopsound( "mus_fire_sale" ); + } + level waittill( "firesale_over" ); + self stoploopsound(); +} + +free_perk_powerup( item ) //checked changed to match cerberus output +{ + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + if ( !players[ i ] maps/mp/zombies/_zm_laststand::player_is_in_laststand() && players[ i ].sessionstate != "spectator" ) + { + player = players[ i ]; + if ( isDefined( item.ghost_powerup ) ) + { + player maps/mp/zombies/_zm_stats::increment_client_stat( "buried_ghost_perk_acquired", 0 ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "buried_ghost_perk_acquired" ); + player notify( "player_received_ghost_round_free_perk" ); + } + free_perk = player maps/mp/zombies/_zm_perks::give_random_perk(); + if ( is_true( level.disable_free_perks_before_power ) ) + { + player thread disable_perk_before_power( free_perk ); + } + } + } +} + +disable_perk_before_power( perk ) //checked matches cerberus output +{ + self endon( "disconnect" ); + if ( isDefined( perk ) ) + { + wait 0.1; + if ( !flag( "power_on" ) ) + { + a_players = get_players(); + if ( isDefined( a_players ) && a_players.size == 1 && perk == "specialty_quickrevive" ) + { + return; + } + self perk_pause( perk ); + flag_wait( "power_on" ); + self perk_unpause( perk ); + } + } +} + +random_weapon_powerup_throttle() //checked matches cerberus output +{ + self.random_weapon_powerup_throttle = 1; + wait 0.25; + self.random_weapon_powerup_throttle = 0; +} + +random_weapon_powerup( item, player ) //checked partially matches cerberus output did not change +{ + if ( player.sessionstate == "spectator" || player maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + return 0; + } + if ( !is_true( player.random_weapon_powerup_throttle ) || player isswitchingweapons() && player.is_drinking > 0 ) + { + return 0; + } + current_weapon = player getcurrentweapon(); + current_weapon_type = weaponinventorytype( current_weapon ); + if ( !is_tactical_grenade( item.weapon ) ) + { + if ( current_weapon_type != "primary" && current_weapon_type != "altmode" ) + { + return 0; + } + if ( !isDefined( level.zombie_weapons[ current_weapon ] ) && !maps/mp/zombies/_zm_weapons::is_weapon_upgraded( current_weapon ) && current_weapon_type != "altmode" ) + { + return 0; + } + } + player thread random_weapon_powerup_throttle(); + weapon_string = item.weapon; + if ( weapon_string == "knife_ballistic_zm" ) + { + weapon = player maps/mp/zombies/_zm_melee_weapon::give_ballistic_knife( weapon_string, 0 ); + } + else + { + if ( weapon_string == "knife_ballistic_upgraded_zm" ) + { + weapon = player maps/mp/zombies/_zm_melee_weapon::give_ballistic_knife( weapon_string, 1 ); + } + } + player thread maps/mp/zombies/_zm_weapons::weapon_give( weapon_string ); + return 1; +} + +bonus_points_player_powerup( item, player ) //checked matches cerberus output +{ + points = randomintrange( 1, 25 ) * 100; + if ( isDefined( level.bonus_points_powerup_override ) ) + { + points = [[ level.bonus_points_powerup_override ]](); + } + if ( !player maps/mp/zombies/_zm_laststand::player_is_in_laststand() && player.sessionstate != "spectator" ) + { + player maps/mp/zombies/_zm_score::player_add_points( "bonus_points_powerup", points ); + } +} + +bonus_points_team_powerup( item ) //checked changed to match cerberus output +{ + points = randomintrange( 1, 25 ) * 100; + if ( isDefined( level.bonus_points_powerup_override ) ) + { + points = [[ level.bonus_points_powerup_override ]](); + } + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + if ( !players[ i ] maps/mp/zombies/_zm_laststand::player_is_in_laststand() && players[ i ].sessionstate != "spectator" ) + { + players[ i ] maps/mp/zombies/_zm_score::player_add_points( "bonus_points_powerup", points ); + } + } +} + +lose_points_team_powerup( item ) //checked partially changed to match cerberus output +{ + points = randomintrange( 1, 25 ) * 100; + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( !players[ i ] maps/mp/zombies/_zm_laststand::player_is_in_laststand() && players[ i ].sessionstate != "spectator" ) + { + if ( ( players[ i ].score - points ) <= 0 ) + { + players[ i ] maps/mp/zombies/_zm_score::minus_to_player_score( players[ i ].score ); + i++; + continue; + } + else + { + players[ i ] maps/mp/zombies/_zm_score::minus_to_player_score( points ); + } + } + i++; + } +} + +lose_perk_powerup( item ) //checked partially matches cerberus output +{ + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + player = players[ i ]; + if ( !player maps/mp/zombies/_zm_laststand::player_is_in_laststand() && player.sessionstate != "spectator" ) + { + player maps/mp/zombies/_zm_perks::lose_random_perk(); + } + } +} + +empty_clip_powerup( item ) //checked partially matches cerberus output +{ + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + player = players[ i ]; + if ( !player maps/mp/zombies/_zm_laststand::player_is_in_laststand() && player.sessionstate != "spectator" ) + { + weapon = player getcurrentweapon(); + player setweaponammoclip( weapon, 0 ); + } + } +} + +minigun_weapon_powerup( ent_player, time ) //checked matches cerberus output +{ + ent_player endon( "disconnect" ); + ent_player endon( "death" ); + ent_player endon( "player_downed" ); + if ( !isDefined( time ) ) + { + time = 30; + } + if ( isDefined( level._minigun_time_override ) ) + { + time = level._minigun_time_override; + } + if ( ent_player.zombie_vars[ "zombie_powerup_minigun_on" ] || ent_player getcurrentweapon() == "minigun_zm" && is_true( ent_player.has_minigun ) ) + { + if ( ent_player.zombie_vars[ "zombie_powerup_minigun_time" ] < time ) + { + ent_player.zombie_vars[ "zombie_powerup_minigun_time" ] = time; + } + return; + } + ent_player notify( "replace_weapon_powerup" ); + ent_player._show_solo_hud = 1; + level._zombie_minigun_powerup_last_stand_func = ::minigun_watch_gunner_downed; + ent_player.has_minigun = 1; + ent_player.has_powerup_weapon = 1; + ent_player increment_is_drinking(); + ent_player._zombie_gun_before_minigun = ent_player getcurrentweapon(); + ent_player giveweapon( "minigun_zm" ); + ent_player switchtoweapon( "minigun_zm" ); + ent_player.zombie_vars[ "zombie_powerup_minigun_on" ] = 1; + level thread minigun_weapon_powerup_countdown( ent_player, "minigun_time_over", time ); + level thread minigun_weapon_powerup_replace( ent_player, "minigun_time_over" ); +} + +minigun_weapon_powerup_countdown( ent_player, str_gun_return_notify, time ) //checked matches cerberus output +{ + ent_player endon( "death" ); + ent_player endon( "disconnect" ); + ent_player endon( "player_downed" ); + ent_player endon( str_gun_return_notify ); + ent_player endon( "replace_weapon_powerup" ); + setclientsysstate( "levelNotify", "minis", ent_player ); + ent_player.zombie_vars[ "zombie_powerup_minigun_time" ] = time; + while ( ent_player.zombie_vars[ "zombie_powerup_minigun_time" ] > 0 ) + { + wait 0.05; + ent_player.zombie_vars[ "zombie_powerup_minigun_time" ] -= 0.05; + } + setclientsysstate( "levelNotify", "minie", ent_player ); + level thread minigun_weapon_powerup_remove( ent_player, str_gun_return_notify ); +} + +minigun_weapon_powerup_replace( ent_player, str_gun_return_notify ) //checked matches cerberus output +{ + ent_player endon( "death" ); + ent_player endon( "disconnect" ); + ent_player endon( "player_downed" ); + ent_player endon( str_gun_return_notify ); + ent_player waittill( "replace_weapon_powerup" ); + ent_player takeweapon( "minigun_zm" ); + ent_player.zombie_vars[ "zombie_powerup_minigun_on" ] = 0; + ent_player.has_minigun = 0; + ent_player decrement_is_drinking(); +} + +minigun_weapon_powerup_remove( ent_player, str_gun_return_notify ) //checked partially matches cerberus output did not change +{ + ent_player endon( "death" ); + ent_player endon( "player_downed" ); + ent_player takeweapon( "minigun_zm" ); + ent_player.zombie_vars[ "zombie_powerup_minigun_on" ] = 0; + ent_player._show_solo_hud = 0; + ent_player.has_minigun = 0; + ent_player.has_powerup_weapon = 0; + ent_player notify( str_gun_return_notify ); + ent_player decrement_is_drinking(); + while ( isDefined( ent_player._zombie_gun_before_minigun ) ) + { + player_weapons = ent_player getweaponslistprimaries(); + + for ( i = 0; i < player_weapons.size; i++ ) + { + if ( player_weapons[ i ] == ent_player._zombie_gun_before_minigun ) + { + ent_player switchtoweapon( ent_player._zombie_gun_before_minigun ); + return; + } + } + } + primaryweapons = ent_player getweaponslistprimaries(); + if ( primaryweapons.size > 0 ) + { + ent_player switchtoweapon( primaryweapons[ 0 ] ); + } + else + { + allweapons = ent_player getweaponslist( 1 ); + for ( i = 0; i < allweapons.size; i++ ) + { + if ( is_melee_weapon( allweapons[ i ] ) ) + { + ent_player switchtoweapon( allweapons[ i ] ); + return; + } + } + } +} + +minigun_weapon_powerup_off() //checked matches cerberus output +{ + self.zombie_vars[ "zombie_powerup_minigun_time" ] = 0; +} + +minigun_watch_gunner_downed() //checked partially matches cerberus output did not change +{ + if ( !is_true( self.has_minigun ) ) + { + return; + } + primaryweapons = self getweaponslistprimaries(); + for ( i = 0; i < primaryweapons.size; i++ ) + { + if ( primaryweapons[ i ] == "minigun_zm" ) + { + self takeweapon( "minigun_zm" ); + } + } + self notify( "minigun_time_over" ); + self.zombie_vars[ "zombie_powerup_minigun_on" ] = 0; + self._show_solo_hud = 0; + wait 0.05; + self.has_minigun = 0; + self.has_powerup_weapon = 0; +} + +tesla_weapon_powerup( ent_player, time ) //checked changed to match cerberus output +{ + ent_player endon( "disconnect" ); + ent_player endon( "death" ); + ent_player endon( "player_downed" ); + if ( !isDefined( time ) ) + { + time = 11; + } + if ( ent_player.zombie_vars[ "zombie_powerup_tesla_on" ] && ent_player getcurrentweapon() == "tesla_gun_zm" || is_true( ent_player.has_tesla ) ) + { + ent_player givemaxammo( "tesla_gun_zm" ); + if ( ent_player.zombie_vars[ "zombie_powerup_tesla_time" ] < time ) + { + ent_player.zombie_vars[ "zombie_powerup_tesla_time" ] = time; + } + return; + } + ent_player notify( "replace_weapon_powerup" ); + ent_player._show_solo_hud = 1; + level._zombie_tesla_powerup_last_stand_func = ::tesla_watch_gunner_downed; + ent_player.has_tesla = 1; + ent_player.has_powerup_weapon = 1; + ent_player increment_is_drinking(); + ent_player._zombie_gun_before_tesla = ent_player getcurrentweapon(); + ent_player giveweapon( "tesla_gun_zm" ); + ent_player givemaxammo( "tesla_gun_zm" ); + ent_player switchtoweapon( "tesla_gun_zm" ); + ent_player.zombie_vars[ "zombie_powerup_tesla_on" ] = 1; + level thread tesla_weapon_powerup_countdown( ent_player, "tesla_time_over", time ); + level thread tesla_weapon_powerup_replace( ent_player, "tesla_time_over" ); +} + +tesla_weapon_powerup_countdown( ent_player, str_gun_return_notify, time ) //checked changed to match cerberus output +{ + ent_player endon( "death" ); + ent_player endon( "player_downed" ); + ent_player endon( str_gun_return_notify ); + ent_player endon( "replace_weapon_powerup" ); + setclientsysstate( "levelNotify", "minis", ent_player ); + ent_player.zombie_vars[ "zombie_powerup_tesla_time" ] = time; + while ( 1 ) + { + ent_player waittill_any( "weapon_fired", "reload", "zmb_max_ammo" ); + if ( !ent_player getweaponammostock( "tesla_gun_zm" ) ) + { + clip_count = ent_player getweaponammoclip( "tesla_gun_zm" ); + if ( !clip_count ) + { + break; + } + else if ( clip_count == 1 ) + { + ent_player.zombie_vars[ "zombie_powerup_tesla_time" ] = 1; + } + else if ( clip_count == 3 ) + { + ent_player.zombie_vars[ "zombie_powerup_tesla_time" ] = 6; + } + } + else + { + ent_player.zombie_vars[ "zombie_powerup_tesla_time" ] = 11; + } + } + setclientsysstate( "levelNotify", "minie", ent_player ); + level thread tesla_weapon_powerup_remove( ent_player, str_gun_return_notify ); +} + +tesla_weapon_powerup_replace( ent_player, str_gun_return_notify ) //checked matches cerberus output +{ + ent_player endon( "death" ); + ent_player endon( "disconnect" ); + ent_player endon( "player_downed" ); + ent_player endon( str_gun_return_notify ); + ent_player waittill( "replace_weapon_powerup" ); + ent_player takeweapon( "tesla_gun_zm" ); + ent_player.zombie_vars[ "zombie_powerup_tesla_on" ] = 0; + ent_player.has_tesla = 0; + ent_player decrement_is_drinking(); +} + +tesla_weapon_powerup_remove( ent_player, str_gun_return_notify ) //checked changed to match cerberus output +{ + ent_player endon( "death" ); + ent_player endon( "player_downed" ); + ent_player takeweapon( "tesla_gun_zm" ); + ent_player.zombie_vars[ "zombie_powerup_tesla_on" ] = 0; + ent_player._show_solo_hud = 0; + ent_player.has_tesla = 0; + ent_player.has_powerup_weapon = 0; + ent_player notify( str_gun_return_notify ); + ent_player decrement_is_drinking(); + if ( isDefined( ent_player._zombie_gun_before_tesla ) ) + { + player_weapons = ent_player getweaponslistprimaries(); + for ( i = 0; i < player_weapons.size; i++ ) + { + if ( player_weapons[ i ] == ent_player._zombie_gun_before_tesla ) + { + ent_player switchtoweapon( ent_player._zombie_gun_before_tesla ); + return; + } + } + } + primaryweapons = ent_player getweaponslistprimaries(); + if ( primaryweapons.size > 0 ) + { + ent_player switchtoweapon( primaryweapons[ 0 ] ); + } + allweapons = ent_player getweaponslist( 1 ); + for ( i = 0; i < allweapons.size; i++ ) + { + if ( is_melee_weapon( allweapons[ i ] ) ) + { + ent_player switchtoweapon( allweapons[ i ] ); + return; + } + } +} + +tesla_weapon_powerup_off() //checked matches cerberus output +{ + self.zombie_vars[ "zombie_powerup_tesla_time" ] = 0; +} + +tesla_watch_gunner_downed() //checked changed to match cerberus output +{ + if ( !is_true( self.has_tesla ) ) + { + return; + } + primaryweapons = self getweaponslistprimaries(); + for ( i = 0; i < primaryweapons.size; i++ ) + { + if ( primaryweapons[ i ] == "tesla_gun_zm" ) + { + self takeweapon( "tesla_gun_zm" ); + } + } + self notify( "tesla_time_over" ); + self.zombie_vars[ "zombie_powerup_tesla_on" ] = 0; + self._show_solo_hud = 0; + wait 0.05; + self.has_tesla = 0; + self.has_powerup_weapon = 0; +} + +tesla_powerup_active() //checked changed to match cerberus output +{ + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + if ( players[ i ].zombie_vars[ "zombie_powerup_tesla_on" ] ) + { + return 1; + } + } + return 0; +} + +print_powerup_drop( powerup, type ) //devcall only, deleted +{ + /* + /# + if(!isdefined(level.powerup_drop_time)) + { + level.powerup_drop_time = 0; + level.powerup_random_count = 0; + level.powerup_score_count = 0; + } + time = GetTime() - level.powerup_drop_time * 0.001; + level.powerup_drop_time = GetTime(); + if(type == "random") + { + level.powerup_random_count++; + } + else + { + level.powerup_score_count++; + } + println("========== POWER UP DROPPED =========="); + println("DROPPED: " + powerup); + println("HOW IT DROPPED: " + type); + println("--------------------"); + println("Drop Time: " + time); + println("Random Powerup Count: " + level.powerup_random_count); + println("Random Powerup Count: " + level.powerup_score_count); + println("======================================"); + #/ + */ +} + +register_carpenter_node( node, callback ) //checked matches cerberus output +{ + if ( !isDefined( level._additional_carpenter_nodes ) ) + { + level._additional_carpenter_nodes = []; + } + node._post_carpenter_callback = callback; + level._additional_carpenter_nodes[ level._additional_carpenter_nodes.size ] = node; +} + +start_carpenter_new( origin ) //checked partially changed to match cerberus output +{ + level.carpenter_powerup_active = 1; + window_boards = getstructarray( "exterior_goal", "targetname" ); + if ( isDefined( level._additional_carpenter_nodes ) ) + { + window_boards = arraycombine( window_boards, level._additional_carpenter_nodes, 0, 0 ); + } + carp_ent = spawn( "script_origin", ( 0, 0, 0 ) ); + carp_ent playloopsound( "evt_carpenter" ); + boards_near_players = get_near_boards( window_boards ); + boards_far_from_players = get_far_boards( window_boards ); + level repair_far_boards( boards_far_from_players, maps/mp/zombies/_zm_powerups::is_carpenter_boards_upgraded() ); + + i = 0; + while ( i < boards_near_players.size ) + { + window = boards_near_players[ i ]; + num_chunks_checked = 0; + last_repaired_chunk = undefined; + while ( 1 ) + { + if ( all_chunks_intact( window, window.barrier_chunks ) ) + { + break; + } + chunk = get_random_destroyed_chunk( window, window.barrier_chunks ); + if ( !isDefined( chunk ) ) + { + break; + } + window thread maps/mp/zombies/_zm_blockers::replace_chunk( window, chunk, undefined, maps/mp/zombies/_zm_powerups::is_carpenter_boards_upgraded(), 1 ); + last_repaired_chunk = chunk; + if ( isDefined( window.clip ) ) + { + window.clip enable_trigger(); + window.clip disconnectpaths(); + } + else + { + blocker_disconnect_paths( window.neg_start, window.neg_end ); + } + wait_network_frame(); + num_chunks_checked++; + if ( num_chunks_checked >= 20 ) + { + break; + } + } + if ( isDefined( window.zbarrier ) ) + { + if ( isDefined( last_repaired_chunk ) ) + { + while ( window.zbarrier getzbarrierpiecestate( last_repaired_chunk ) == "closing" ) + { + wait 0.05; + } + if ( isDefined( window._post_carpenter_callback ) ) + { + window [[ window._post_carpenter_callback ]](); + } + } + i++; + continue; + } + while ( isDefined( last_repaired_chunk ) && last_repaired_chunk.state == "mid_repair" ) + { + wait 0.05; + } + i++; + } + carp_ent stoploopsound( 1 ); + carp_ent playsoundwithnotify( "evt_carpenter_end", "sound_done" ); + carp_ent waittill( "sound_done" ); + players = get_players(); + for ( i = 0; i < players.size; i++ ) + { + players[ i ] maps/mp/zombies/_zm_score::player_add_points( "carpenter_powerup", 200 ); + } + carp_ent delete(); + level notify( "carpenter_finished" ); + level.carpenter_powerup_active = undefined; +} + +is_carpenter_boards_upgraded() //checked matches cerberus output +{ + if ( isDefined( level.pers_carpenter_boards_active ) && level.pers_carpenter_boards_active == 1 ) + { + return 1; + } + return 0; +} + +get_near_boards( windows ) //checked changed to match cerberus output +{ + players = get_players(); + boards_near_players = []; + for ( j = 0; j < windows.size; j++ ) + { + close = 0; + for ( i = 0; i < players.size; i++ ) + { + origin = undefined; + if ( isdefined( windows[ j ].zbarrier ) ) + { + origin = windows[ j ].zbarrier.origin; + } + else + { + origin = windows[ j ].origin; + } + if ( distancesquared( players[ i ].origin, origin ) <= level.board_repair_distance_squared ) + { + close = 1; + break; + } + } + if ( close ) + { + boards_near_players[ boards_near_players.size ] = windows[ j ]; + } + } + return boards_near_players; +} + +get_far_boards( windows ) //checked changed to match cerberus output +{ + players = get_players(); + boards_far_from_players = []; + for ( j = 0; j < windows.size; j++ ) + { + close = 0; + for ( i = 0; i < players.size; i++ ) + { + origin = undefined; + if ( isdefined( windows[ j ].zbarrier ) ) + { + origin = windows[ j ].zbarrier.origin; + } + else + { + origin = windows[ j ].origin; + } + if ( distancesquared( players[ i ].origin, origin ) >= level.board_repair_distance_squared ) + { + close = 1; + break; + } + } + if ( close ) + { + boards_far_from_players[ boards_far_from_players.size ] = windows[ j ]; + } + } + return boards_far_from_players; +} + +repair_far_boards( barriers, upgrade ) //checked changed to match cerberus output +{ + i = 0; + while ( i < barriers.size ) + { + barrier = barriers[ i ]; + if ( all_chunks_intact( barrier, barrier.barrier_chunks ) ) + { + i++; + continue; + } + if ( isdefined( barrier.zbarrier ) ) + { + a_pieces = barrier.zbarrier getzbarrierpieceindicesinstate( "open" ); + if ( isdefined( a_pieces ) ) + { + xx = 0; + while ( xx < a_pieces.size ) + { + chunk = a_pieces[ xx ]; + if ( upgrade ) + { + barrier.zbarrier zbarrierpieceuseupgradedmodel( chunk ); + barrier.zbarrier.chunk_health[ chunk ] = barrier.zbarrier getupgradedpiecenumlives( chunk ); + xx++; + continue; + } + barrier.zbarrier zbarrierpieceusedefaultmodel( chunk ); + barrier.zbarrier.chunk_health[ chunk ] = 0; + xx++; + } + } + for ( x = 0; x < barrier.zbarrier getnumzbarrierpieces(); x++ ) + { + barrier.zbarrier setzbarrierpiecestate( x, "closed" ); + barrier.zbarrier showzbarrierpiece( x ); + } + } + else if ( isdefined( barrier.clip ) ) + { + barrier.clip enable_trigger(); + barrier.clip disconnectpaths(); + } + else + { + blocker_disconnect_paths( barrier.neg_start, barrier.neg_end ); + } + if ( i % 4 == 0 ) + { + wait_network_frame(); + } + i++; + } +} + +func_should_never_drop() //checked matches cerberus output +{ + return 0; +} + +func_should_always_drop() //checked matches cerberus output +{ + return 1; +} + +func_should_drop_minigun() //checked matches cerberus output +{ + if ( minigun_no_drop() ) + { + return 0; + } + return 1; +} + +func_should_drop_carpenter() //checked matches cerberus output +{ + if ( get_num_window_destroyed() < 5 ) + { + return 0; + } + return 1; +} + +func_should_drop_fire_sale() //checked partially changed to match cerberus output +{ + if ( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] == 1 || level.chest_moves < 1 || is_true( level.disable_firesale_drop ) ) + { + return 0; + } + return 1; +} + +powerup_move() //checked partially changed to match cerberus output +{ + self endon( "powerup_timedout" ); + self endon( "powerup_grabbed" ); + drag_speed = 75; + while ( 1 ) + { + self waittill( "move_powerup", moveto, distance ); + drag_vector = moveto - self.origin; + range_squared = lengthsquared( drag_vector ); + if ( range_squared > distance * distance ) + { + drag_vector = vectornormalize( drag_vector ); + drag_vector = distance * drag_vector; + moveto = self.origin + drag_vector; + } + self.origin = moveto; + } +} + +powerup_emp() //checked matches cerberus output +{ + self endon( "powerup_timedout" ); + self endon( "powerup_grabbed" ); + if ( !should_watch_for_emp() ) + { + return; + } + while ( 1 ) + { + level waittill( "emp_detonate", origin, radius ); + if ( distancesquared( origin, self.origin ) < ( radius * radius ) ) + { + playfx( level._effect[ "powerup_off" ], self.origin ); + self thread powerup_delete_delayed(); + self notify( "powerup_timedout" ); + } + } +} + +get_powerups( origin, radius ) //checked changed to match cerberus output +{ + if ( isDefined( origin ) && isDefined( radius ) ) + { + powerups = []; + foreach ( powerup in level.active_powerups ) + { + if ( distancesquared( origin, powerup.origin ) < radius * radius ) + { + powerups[ powerups.size ] = powerup; + } + } + return powerups; + } + return level.active_powerups; +} + +should_award_stat( powerup_name ) //checked changed to matched cerberus output +{ + if ( powerup_name == "teller_withdrawl" || powerup_name == "blue_monkey" || powerup_name == "free_perk" || powerup_name == "bonus_points_player" ) + { + return 0; + } + if ( isDefined( level.statless_powerups ) && isDefined( level.statless_powerups[ powerup_name ] ) ) + { + return 0; + } + return 1; +} + +teller_withdrawl( powerup, player ) //checked matches cerberus output +{ + player maps/mp/zombies/_zm_score::add_to_player_score( powerup.value ); +} + + + + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_spawner.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_spawner.gsc new file mode 100644 index 0000000..34889df --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_spawner.gsc @@ -0,0 +1,3290 @@ +#include maps/mp/zombies/_zm_ai_faller; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm; +#include maps/mp/zombies/_zm_pers_upgrades_functions; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_pers_upgrades; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/animscripts/zm_run; +#include maps/mp/animscripts/zm_death; +#include maps/mp/zombies/_zm_blockers; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/animscripts/zm_shared; +#include maps/mp/animscripts/zm_utility; +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() //checked changed to match cerberus output +{ + level._contextual_grab_lerp_time = 0.3; + level.zombie_spawners = getentarray( "zombie_spawner", "script_noteworthy" ); + if ( is_true( level.use_multiple_spawns ) ) + { + level.zombie_spawn = []; + for ( i = 0; i < level.zombie_spawners.size; i++ ) + { + if ( isDefined( level.zombie_spawners[ i ].script_int ) ) + { + int = level.zombie_spawners[ i ].script_int; + if ( !isDefined( level.zombie_spawn[ int ] ) ) + { + level.zombie_spawn[ int ] = []; + } + level.zombie_spawn[ int ][ level.zombie_spawn[ int ].size ] = level.zombie_spawners[ i ]; + } + } + } + precachemodel( "p6_anim_zm_barricade_board_01_upgrade" ); + precachemodel( "p6_anim_zm_barricade_board_02_upgrade" ); + precachemodel( "p6_anim_zm_barricade_board_03_upgrade" ); + precachemodel( "p6_anim_zm_barricade_board_04_upgrade" ); + precachemodel( "p6_anim_zm_barricade_board_05_upgrade" ); + precachemodel( "p6_anim_zm_barricade_board_06_upgrade" ); + if ( isDefined( level.ignore_spawner_func ) ) + { + for ( i = 0; i < level.zombie_spawners.size; i++ ) + { + ignore = [[ level.ignore_spawner_func ]]( level.zombie_spawners[ i ] ); + if ( ignore ) + { + arrayremovevalue( level.zombie_spawners, level.zombie_spawners[ i ] ); + } + } + } + gametype = getDvar( "ui_gametype" ); + if ( !isDefined( level.attack_player_thru_boards_range ) ) + { + level.attack_player_thru_boards_range = 109.8; + } + if ( isDefined( level._game_module_custom_spawn_init_func ) ) + { + [[ level._game_module_custom_spawn_init_func ]](); + } + registerclientfield( "actor", "zombie_has_eyes", 1, 1, "int" ); + registerclientfield( "actor", "zombie_ragdoll_explode", 1, 1, "int" ); + registerclientfield( "actor", "zombie_gut_explosion", 9000, 1, "int" ); +} + +add_cusom_zombie_spawn_logic( func ) //checked matches cerberus output +{ + if ( !isDefined( level._zombie_custom_spawn_logic ) ) + { + level._zombie_custom_spawn_logic = []; + } + level._zombie_custom_spawn_logic[ level._zombie_custom_spawn_logic.size ] = func; +} + +player_attacks_enemy( player, amount, type, point ) //checked matches cerberus output +{ + team = undefined; + if ( isDefined( self._race_team ) ) + { + team = self._race_team; + } + if ( !isads( player ) ) + { + [[ level.global_damage_func ]]( type, self.damagelocation, point, player, amount, team ); + return 0; + } + if ( !bullet_attack( type ) ) + { + [[ level.global_damage_func ]]( type, self.damagelocation, point, player, amount, team ); + return 0; + } + [[ level.global_damage_func_ads ]]( type, self.damagelocation, point, player, amount, team ); + return 1; +} + +player_attacker( attacker ) //checked matches cerberus output +{ + if ( isplayer( attacker ) ) + { + return 1; + } + return 0; +} + +enemy_death_detection() //checked changed to match cerberus output +{ + self endon( "death" ); + for ( ;; ) + { + self waittill( "damage", amount, attacker, direction_vec, point, type ); + if ( !isDefined( amount ) ) + { + continue; + } + if ( !isalive( self ) || self.delayeddeath ) + { + return; + } + if ( !player_attacker( attacker ) ) + { + continue; + } + self.has_been_damaged_by_player = 1; + self player_attacks_enemy( attacker, amount, type, point ); + } +} + +is_spawner_targeted_by_blocker( ent ) //checked changed to match cerberus output +{ + if ( isDefined( ent.targetname ) ) + { + targeters = getentarray( ent.targetname, "target" ); + for ( i = 0; i < targeters.size; i++ ) + { + if ( targeters[ i ].targetname == "zombie_door" || targeters[ i ].targetname == "zombie_debris" ) + { + return 1; + } + result = is_spawner_targeted_by_blocker( targeters[ i ] ); + if ( result ) + { + return 1; + } + i++; + } + } + return 0; +} + +add_custom_zombie_spawn_logic( func ) //checked matches cerberus output +{ + if ( !isDefined( level._zombie_custom_spawn_logic ) ) + { + level._zombie_custom_spawn_logic = []; + } + level._zombie_custom_spawn_logic[ level._zombie_custom_spawn_logic.size ] = func; +} + +zombie_spawn_init( animname_set ) //checked partially changed to match cerberus output +{ + if ( !isDefined( animname_set ) ) + { + animname_set = 0; + } + self.targetname = "zombie"; + self.script_noteworthy = undefined; + recalc_zombie_array(); + if ( !animname_set ) + { + self.animname = "zombie"; + } + if ( isDefined( get_gamemode_var( "pre_init_zombie_spawn_func" ) ) ) + { + self [[ get_gamemode_var( "pre_init_zombie_spawn_func" ) ]](); + } + self thread play_ambient_zombie_vocals(); + self.zmb_vocals_attack = "zmb_vocals_zombie_attack"; + self.ignoreall = 1; + self.ignoreme = 1; + self.allowdeath = 1; + self.force_gib = 1; + self.is_zombie = 1; + self.has_legs = 1; + self allowedstances( "stand" ); + self.zombie_damaged_by_bar_knockdown = 0; + self.gibbed = 0; + self.head_gibbed = 0; + self setphysparams( 15, 0, 72 ); + self.disablearrivals = 1; + self.disableexits = 1; + self.grenadeawareness = 0; + self.badplaceawareness = 0; + self.ignoresuppression = 1; + self.suppressionthreshold = 1; + self.nododgemove = 1; + self.dontshootwhilemoving = 1; + self.pathenemylookahead = 0; + self.badplaceawareness = 0; + self.chatinitialized = 0; + self.a.disablepain = 1; + + self disable_react(); + if ( isDefined( level.zombie_health ) ) + { + self.maxhealth = level.zombie_health; + if ( isDefined( level.zombie_respawned_health ) && level.zombie_respawned_health.size > 0 ) + { + self.health = level.zombie_respawned_health[ 0 ]; + arrayremovevalue( level.zombie_respawned_health, level.zombie_respawned_health[ 0 ] ); + } + else + { + self.health = level.zombie_health; + } + } + else + { + self.maxhealth = level.zombie_vars[ "zombie_health_start" ]; + self.health = self.maxhealth; + } + self.freezegun_damage = 0; + self.dropweapon = 0; + level thread zombie_death_event( self ); + self init_zombie_run_cycle(); + self thread zombie_think(); + self thread zombie_gib_on_damage(); + self thread zombie_damage_failsafe(); + self thread enemy_death_detection(); + if ( isDefined( level._zombie_custom_spawn_logic ) ) + { + if ( isarray( level._zombie_custom_spawn_logic ) ) + { + for ( i = 0; i < level._zombie_custom_spawn_logic.size; i++ ) + { + self thread [[ level._zombie_custom_spawn_logic[ i ] ]](); + } + } + else + { + self thread [[ level._zombie_custom_spawn_logic ]](); + } + } + if ( !is_true( self.no_eye_glow ) ) + { + if ( !is_true( self.is_inert ) ) //imported from beta dump + { + self thread delayed_zombie_eye_glow(); + } + } + self.deathfunction = ::zombie_death_animscript; + self.flame_damage_time = 0; + self.meleedamage = 60; + self.no_powerups = 1; + self zombie_history( "zombie_spawn_init -> Spawned = " + self.origin ); + self.thundergun_knockdown_func = level.basic_zombie_thundergun_knockdown; + self.tesla_head_gib_func = ::zombie_tesla_head_gib; + self.team = level.zombie_team; + if ( isDefined( level.achievement_monitor_func ) ) + { + self [[ level.achievement_monitor_func ]](); + } + if ( isDefined( get_gamemode_var( "post_init_zombie_spawn_func" ) ) ) + { + self [[ get_gamemode_var( "post_init_zombie_spawn_func" ) ]](); + } + if ( isDefined( level.zombie_init_done ) ) + { + self [[ level.zombie_init_done ]](); + } + self.zombie_init_done = 1; + self notify( "zombie_init_done" ); +} + +delayed_zombie_eye_glow() //checked changed to match cerberus output +{ + self endon( "zombie_delete" ); + if ( is_true( self.in_the_ground ) || is_true( self.in_the_ceiling ) ) + { + while ( !isDefined( self.create_eyes ) ) + { + wait 0.1; + } + } + else + { + wait 0.5; + } + self zombie_eye_glow(); +} + +zombie_damage_failsafe() //checked changed to match cerberus output +{ + self endon( "death" ); + continue_failsafe_damage = 0; + while ( 1 ) + { + wait 0.5; + if ( !isDefined( self.enemy ) || !isplayer( self.enemy ) ) + { + continue; + } + if ( self istouching( self.enemy ) ) + { + old_org = self.origin; + if ( !continue_failsafe_damage ) + { + wait 5; + } + if ( !isDefined( self.enemy ) || !isplayer( self.enemy ) || self.enemy hasperk( "specialty_armorvest" ) ) + { + continue; + } + if ( self istouching( self.enemy ) && !self.enemy maps/mp/zombies/_zm_laststand::player_is_in_laststand() && isalive( self.enemy ) ) + { + if ( distancesquared( old_org, self.origin ) < 3600 ) + { + self.enemy dodamage( self.enemy.health + 1000, self.enemy.origin, self, self, "none", "MOD_RIFLE_BULLET" ); + continue_failsafe_damage = 1; + } + } + } + else + { + continue_failsafe_damage = 0; + } + } +} + +should_skip_teardown( find_flesh_struct_string ) //checked matches cerberus output +{ + if ( isDefined( find_flesh_struct_string ) && find_flesh_struct_string == "find_flesh" ) + { + return 1; + } + if ( isDefined( self.script_string ) && self.script_string == "zombie_chaser" ) + { + return 1; + } + return 0; +} + +zombie_think() //checked changed to match cerberus output +{ + self endon( "death" ); + /* +/# + assert( !self.isdog ); +#/ + */ + self.ai_state = "zombie_think"; + find_flesh_struct_string = undefined; + if ( isDefined( level.zombie_custom_think_logic ) ) + { + shouldwait = self [[ level.zombie_custom_think_logic ]](); + if ( shouldwait ) + { + self waittill( "zombie_custom_think_done", find_flesh_struct_string ); + } + } + else if ( is_true( self.start_inert ) ) + { + find_flesh_struct_string = "find_flesh"; + } + else + { + if ( isDefined( self.custom_location ) ) + { + self thread [[ self.custom_location ]](); + } + else + { + self thread do_zombie_spawn(); + } + self waittill( "risen", find_flesh_struct_string ); + } + node = undefined; + desired_nodes = []; + self.entrance_nodes = []; + if ( isDefined( level.max_barrier_search_dist_override ) ) + { + max_dist = level.max_barrier_search_dist_override; + } + else + { + max_dist = 500; + } + if ( !isDefined( find_flesh_struct_string ) && isDefined( self.target ) && self.target != "" ) + { + desired_origin = get_desired_origin(); + /* +/# + assert( isDefined( desired_origin ), "Spawner @ " + self.origin + " has a .target but did not find a target" ); +#/ + */ + origin = desired_origin; + node = getclosest( origin, level.exterior_goals ); + self.entrance_nodes[ self.entrance_nodes.size ] = node; + self zombie_history( "zombie_think -> #1 entrance (script_forcegoal) origin = " + self.entrance_nodes[ 0 ].origin ); + } + else if ( self should_skip_teardown( find_flesh_struct_string ) ) + { + self zombie_setup_attack_properties(); + if ( isDefined( self.target ) ) + { + end_at_node = getnode( self.target, "targetname" ); + if ( isDefined( end_at_node ) ) + { + self setgoalnode( end_at_node ); + self waittill( "goal" ); + } + } + if ( is_true( self.start_inert ) ) + { + self thread maps/mp/zombies/_zm_ai_basic::start_inert( 1 ); + self zombie_complete_emerging_into_playable_area(); + } + else + { + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + self thread zombie_entered_playable(); + } + return; + } + else if ( isDefined( find_flesh_struct_string ) ) + { + /* +/# + assert( isDefined( find_flesh_struct_string ) ); +#/ + */ + for ( i = 0; i < level.exterior_goals.size; i++ ) + { + if ( isDefined( level.exterior_goals[ i ].script_string ) && level.exterior_goals[ i ].script_string == find_flesh_struct_string ) + { + node = level.exterior_goals[ i ]; + break; + } + } + self.entrance_nodes[ self.entrance_nodes.size ] = node; + self zombie_history( "zombie_think -> #1 entrance origin = " + node.origin ); + self thread zombie_assure_node(); + } + else + { + origin = self.origin; + desired_origin = get_desired_origin(); + if ( isDefined( desired_origin ) ) + { + origin = desired_origin; + } + nodes = get_array_of_closest( origin, level.exterior_goals, undefined, 3 ); + desired_nodes[ 0 ] = nodes[ 0 ]; + prev_dist = distance( self.origin, nodes[ 0 ].origin ); + for ( i = 1; i < nodes.size; i++ ) + { + dist = distance( self.origin, nodes[ i ].origin ); + if ( ( dist - prev_dist ) > max_dist ) + { + break; + } + prev_dist = dist; + desired_nodes[ i ] = nodes[ i ]; + } + node = desired_nodes[ 0 ]; + if ( desired_nodes.size > 1 ) + { + node = desired_nodes[ randomint( desired_nodes.size ) ]; + } + self.entrance_nodes = desired_nodes; + self zombie_history( "zombie_think -> #1 entrance origin = " + node.origin ); + self thread zombie_assure_node(); + } +/* +/# + assert( isDefined( node ), "Did not find a node!!! [Should not see this!]" ); +#/ +*/ + level thread draw_line_ent_to_pos( self, node.origin, "goal" ); + self.first_node = node; + self thread zombie_goto_entrance( node ); +} + +zombie_entered_playable() //checked changed to match cerberus output +{ + self endon( "death" ); + if ( !isDefined( level.playable_areas ) ) + { + level.playable_areas = getentarray( "player_volume", "script_noteworthy" ); + } + while ( 1 ) + { + foreach ( area in level.playable_areas ) + { + if ( self istouching( area ) ) + { + wait 1.5; + self zombie_complete_emerging_into_playable_area(); + return; + } + } + wait 1; + } +} + +get_desired_origin() //checked matches cerberus output +{ + if ( isDefined( self.target ) ) + { + ent = getent( self.target, "targetname" ); + if ( !isDefined( ent ) ) + { + ent = getstruct( self.target, "targetname" ); + } + if ( !isDefined( ent ) ) + { + ent = getnode( self.target, "targetname" ); + } + /* +/# + assert( isDefined( ent ), "Cannot find the targeted ent/node/struct, "" + self.target + "" at " + self.origin ); +#/ + */ + return ent.origin; + } + return undefined; +} + +zombie_goto_entrance( node, endon_bad_path ) //checked matches cerberus output +{ +/* +/# + assert( !self.isdog ); +#/ +*/ + self endon( "death" ); + self endon( "stop_zombie_goto_entrance" ); + level endon( "intermission" ); + self.ai_state = "zombie_goto_entrance"; + if ( is_true( endon_bad_path ) ) + { + self endon( "bad_path" ); + } + self zombie_history( "zombie_goto_entrance -> start goto entrance " + node.origin ); + self.got_to_entrance = 0; + self.goalradius = 128; + self setgoalpos( node.origin ); + self waittill( "goal" ); + self.got_to_entrance = 1; + self zombie_history( "zombie_goto_entrance -> reached goto entrance " + node.origin ); + self tear_into_building(); + if ( isDefined( level.pre_aggro_pathfinding_func ) ) + { + self [[ level.pre_aggro_pathfinding_func ]](); + } + barrier_pos = []; + barrier_pos[ 0 ] = "m"; + barrier_pos[ 1 ] = "r"; + barrier_pos[ 2 ] = "l"; + self.barricade_enter = 1; + animstate = maps/mp/animscripts/zm_utility::append_missing_legs_suffix( "zm_barricade_enter" ); + substate = "barrier_" + self.zombie_move_speed + "_" + barrier_pos[ self.attacking_spot_index ]; + self animscripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, animstate, substate ); + maps/mp/animscripts/zm_shared::donotetracks( "barricade_enter_anim" ); + self zombie_setup_attack_properties(); + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + self.pathenemyfightdist = 4; + self zombie_complete_emerging_into_playable_area(); + self.pathenemyfightdist = 64; + self.barricade_enter = 0; +} + +zombie_assure_node() //checked changed to match cerberus output //changed for loops to while loops to prevent infinite loops with continues +{ + self endon( "death" ); + self endon( "goal" ); + level endon( "intermission" ); + start_pos = self.origin; + if ( isDefined( self.entrance_nodes ) ) + { + for ( i = 0; i < self.entrance_nodes.size; i++ ) + { + if ( self zombie_bad_path() ) + { + self zombie_history( "zombie_assure_node -> assigned assured node = " + self.entrance_nodes[ i ].origin ); + /* +/# + println( "^1Zombie @ " + self.origin + " did not move for 1 second. Going to next closest node @ " + self.entrance_nodes[ i ].origin ); +#/ + */ + level thread draw_line_ent_to_pos( self, self.entrance_nodes[ i ].origin, "goal" ); + self.first_node = self.entrance_nodes[ i ]; + self setgoalpos( self.entrance_nodes[ i ].origin ); + } + else + { + return; + } + } + } + wait 2; + nodes = get_array_of_closest( self.origin, level.exterior_goals, undefined, 20 ); + if ( isDefined( nodes ) ) + { + self.entrance_nodes = nodes; + for ( i = 0; i < self.entrance_nodes.size; i++ ) + { + if ( self zombie_bad_path() ) + { + self zombie_history( "zombie_assure_node -> assigned assured node = " + self.entrance_nodes[ i ].origin ); + /* +/# + println( "^1Zombie @ " + self.origin + " did not move for 1 second. Going to next closest node @ " + self.entrance_nodes[ i ].origin ); +#/ + */ + level thread draw_line_ent_to_pos( self, self.entrance_nodes[ i ].origin, "goal" ); + self.first_node = self.entrance_nodes[ i ]; + self setgoalpos( self.entrance_nodes[ i ].origin ); + } + else + { + return; + } + } + } + self zombie_history( "zombie_assure_node -> failed to find a good entrance point" ); + wait 20; + self dodamage( self.health + 10, self.origin ); + level.zombies_timeout_spawn++; +} + +zombie_bad_path() //checked matches cerberus output +{ + self endon( "death" ); + self endon( "goal" ); + self thread zombie_bad_path_notify(); + self thread zombie_bad_path_timeout(); + self.zombie_bad_path = undefined; + while ( !isDefined( self.zombie_bad_path ) ) + { + wait 0.05; + } + self notify( "stop_zombie_bad_path" ); + return self.zombie_bad_path; +} + +zombie_bad_path_notify() //checked matches cerberus output +{ + self endon( "death" ); + self endon( "stop_zombie_bad_path" ); + self waittill( "bad_path" ); + self.zombie_bad_path = 1; +} + +zombie_bad_path_timeout() //checked matches cerberus output +{ + self endon( "death" ); + self endon( "stop_zombie_bad_path" ); + wait 2; + self.zombie_bad_path = 0; +} + +tear_into_building() //checked changed to match cerberus output +{ + self endon( "death" ); + self endon( "teleporting" ); + self zombie_history( "tear_into_building -> start" ); + while ( 1 ) + { + if ( isDefined( self.first_node.script_noteworthy ) ) + { + if ( self.first_node.script_noteworthy == "no_blocker" ) + { + return; + } + } + if ( !isDefined( self.first_node.target ) ) + { + return; + } + if ( all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) ) + { + self zombie_history( "tear_into_building -> all chunks destroyed" ); + } + if ( !get_attack_spot( self.first_node ) ) + { + self zombie_history( "tear_into_building -> Could not find an attack spot" ); + self thread do_a_taunt(); + wait 0.5; + continue; + } + self.goalradius = 2; + if ( isDefined( level.tear_into_position ) ) + { + self [[ level.tear_into_position ]](); + } + else + { + angles = self.first_node.zbarrier.angles; + self setgoalpos( self.attacking_spot, angles ); + } + self waittill( "goal" ); + if ( isDefined( level.tear_into_wait ) ) + { + self [[ level.tear_into_wait ]](); + } + else + { + self waittill_notify_or_timeout( "orientdone", 1 ); + } + self zombie_history( "tear_into_building -> Reach position and orientated" ); + if ( all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) ) + { + self zombie_history( "tear_into_building -> all chunks destroyed" ); + for ( i = 0; i < self.first_node.attack_spots_taken.size; i++ ) + { + self.first_node.attack_spots_taken[ i ] = 0; + } + return; + } + while ( 1 ) + { + if ( isDefined( self.zombie_board_tear_down_callback ) ) + { + self [[ self.zombie_board_tear_down_callback ]](); + } + chunk = get_closest_non_destroyed_chunk( self.origin, self.first_node, self.first_node.barrier_chunks ); + if ( !isDefined( chunk ) ) + { + if ( !all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) ) + { + attack = self should_attack_player_thru_boards(); + if ( !is_true( attack ) && self.has_legs ) + { + self do_a_taunt(); + } + else + { + wait 0.1; + } + continue; + } + for ( i = 0; i < self.first_node.attack_spots_taken.size; i++ ) + { + self.first_node.attack_spots_taken[ i ] = 0; + } + return; + } + self zombie_history( "tear_into_building -> animating" ); + self.first_node.zbarrier setzbarrierpiecestate( chunk, "targetted_by_zombie" ); + self.first_node thread check_zbarrier_piece_for_zombie_inert( chunk, self.first_node.zbarrier, self ); + self.first_node thread check_zbarrier_piece_for_zombie_death( chunk, self.first_node.zbarrier, self ); + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "teardown", self.animname ); + if ( isDefined( level.zbarrier_override_tear_in ) ) + { + animstatebase = self [[ level.zbarrier_override_tear_in ]]( chunk ); + } + else + { + animstatebase = self.first_node.zbarrier getzbarrierpieceanimstate( chunk ); + } + animsubstate = "spot_" + self.attacking_spot_index + "_piece_" + self.first_node.zbarrier getzbarrierpieceanimsubstate( chunk ); + anim_sub_index = self getanimsubstatefromasd( animstatebase + "_in", animsubstate ); + self animscripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, maps/mp/animscripts/zm_utility::append_missing_legs_suffix( animstatebase + "_in" ), anim_sub_index ); + self zombie_tear_notetracks( "tear_anim", chunk, self.first_node ); + while ( self.first_node.zbarrier.chunk_health[ chunk ] > 0 ) + { + self animscripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, maps/mp/animscripts/zm_utility::append_missing_legs_suffix( animstatebase + "_loop" ), anim_sub_index ); + self zombie_tear_notetracks( "tear_anim", chunk, self.first_node ); + self.first_node.zbarrier.chunk_health[ chunk ]--; + + } + self animscripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, maps/mp/animscripts/zm_utility::append_missing_legs_suffix( animstatebase + "_out" ), anim_sub_index ); + self zombie_tear_notetracks( "tear_anim", chunk, self.first_node ); + self.lastchunk_destroy_time = getTime(); + attack = self should_attack_player_thru_boards(); + if ( !is_true( attack ) && self.has_legs ) + { + self do_a_taunt(); + } + if ( all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) ) + { + for ( i = 0; i < self.first_node.attack_spots_taken.size; i++ ) + { + self.first_node.attack_spots_taken[ i ] = 0; + } + level notify( "last_board_torn", self.first_node.zbarrier.origin ); + return; + } + } + self reset_attack_spot(); + } +} + +do_a_taunt() //checked matches cerberus output +{ + self endon( "death" ); + if ( !self.has_legs ) + { + return 0; + } + if ( !self.first_node.zbarrier zbarriersupportszombietaunts() ) + { + return; + } + self.old_origin = self.origin; + if ( getDvar( "zombie_taunt_freq" ) == "" ) + { + setdvar( "zombie_taunt_freq", "5" ); + } + freq = getDvarInt( "zombie_taunt_freq" ); + if ( freq >= randomint( 100 ) ) + { + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "taunt", self.animname ); + tauntstate = "zm_taunt"; + if ( isDefined( self.first_node.zbarrier ) && self.first_node.zbarrier getzbarriertauntanimstate() != "" ) + { + tauntstate = self.first_node.zbarrier getzbarriertauntanimstate(); + } + self animscripted( self.origin, self.angles, tauntstate ); + self taunt_notetracks( "taunt_anim" ); + } +} + +taunt_notetracks( msg ) //see info.md No 8. +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( "taunt_anim", notetrack ); + if ( notetrack == "end" ) + { + self forceteleport( self.old_origin ); + return; + } + } +} + +should_attack_player_thru_boards() //checked changed to match cerberus output +{ + if ( !self.has_legs ) + { + return 0; + } + if ( isDefined( self.first_node.zbarrier ) ) + { + if ( !self.first_node.zbarrier zbarriersupportszombiereachthroughattacks() ) + { + return 0; + } + } + if ( getDvar( "zombie_reachin_freq" ) == "" ) + { + setdvar( "zombie_reachin_freq", "50" ); + } + freq = getDvarInt( "zombie_reachin_freq" ); + players = get_players(); + attack = 0; + self.player_targets = []; + for ( i = 0; i < players.size; i++ ) + { + if ( isalive( players[ i ] ) && !isDefined( players[ i ].revivetrigger ) && distance2d( self.origin, players[ i ].origin ) <= level.attack_player_thru_boards_range && !is_true( players[ i ].zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) ) + { + self.player_targets[ self.player_targets.size ] = players[ i ]; + attack = 1; + } + } + if ( !attack || freq < randomint( 100 ) ) + { + return 0; + } + self.old_origin = self.origin; + attackanimstate = "zm_window_melee"; + if ( isDefined( self.first_node.zbarrier ) && self.first_node.zbarrier getzbarrierreachthroughattackanimstate() != "" ) + { + attackanimstate = self.first_node.zbarrier getzbarrierreachthroughattackanimstate(); + } + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "attack", self.animname ); + self animscripted( self.origin, self.angles, attackanimstate, self.attacking_spot_index - 1 ); + self window_notetracks( "window_melee_anim" ); + return 1; +} + +window_notetracks( msg ) //see info.md No 8. +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( "window_melee_anim", notetrack ); + if ( notetrack == "end" ) + { + self teleport( self.old_origin ); + return; + } + if ( notetrack == "fire" ) + { + if ( self.ignoreall ) + { + self.ignoreall = 0; + } + if ( isDefined( self.first_node ) ) + { + _melee_dist_sq = 8100; + if ( isDefined( level.attack_player_thru_boards_range ) ) + { + _melee_dist_sq = level.attack_player_thru_boards_range * level.attack_player_thru_boards_range; + } + _trigger_dist_sq = 2601; + for ( i = 0; i < self.player_targets.size; i++ ) + { + playerdistsq = distance2dsquared( self.player_targets[ i ].origin, self.origin ); + heightdiff = abs( self.player_targets[ i ].origin[ 2 ] - self.origin[ 2 ] ); + if ( playerdistsq < _melee_dist_sq && ( heightdiff * heightdiff ) < _melee_dist_sq ) + { + triggerdistsq = distance2dsquared( self.player_targets[ i ].origin, self.first_node.trigger_location.origin ); + heightdiff = abs( self.player_targets[ i ].origin[ 2 ] - self.first_node.trigger_location.origin[ 2 ] ); + if ( triggerdistsq < _trigger_dist_sq && ( heightdiff * heightdiff ) < _trigger_dist_sq ) + { + self.player_targets[ i ] dodamage( self.meleedamage, self.origin, self, self, "none", "MOD_MELEE" ); + break; + } + } + } + } + else + { + self melee(); + } + } + } +} + +reset_attack_spot() //checked matches cerberus output +{ + if ( isDefined( self.attacking_node ) ) + { + node = self.attacking_node; + index = self.attacking_spot_index; + node.attack_spots_taken[ index ] = 0; + self.attacking_node = undefined; + self.attacking_spot_index = undefined; + } +} + +get_attack_spot( node ) //checked matches cerberus output +{ + index = get_attack_spot_index( node ); + if ( !isDefined( index ) ) + { + return 0; + } + self.attacking_node = node; + self.attacking_spot_index = index; + node.attack_spots_taken[ index ] = 1; + self.attacking_spot = node.attack_spots[ index ]; + return 1; +} + +get_attack_spot_index( node ) //checked changed to match cerberus output +{ + indexes = []; + for ( i = 0; i < node.attack_spots.size; i++ ) + { + if ( !node.attack_spots_taken[ i ] ) + { + indexes[ indexes.size ] = i; + } + } + if ( indexes.size == 0 ) + { + return undefined; + } + return indexes[ randomint( indexes.size ) ]; +} + +zombie_tear_notetracks( msg, chunk, node ) //checked again see info.md No 8. +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( "tear_anim", notetrack ); //fix for the compiler + if ( notetrack == "end" ) + { + return; + } + if ( notetrack == "board" || notetrack == "destroy_piece" || notetrack == "bar" ) + { + if ( isDefined( level.zbarrier_zombie_tear_notetrack_override ) ) + { + self thread [[ level.zbarrier_zombie_tear_notetrack_override ]]( node, chunk ); + } + node.zbarrier setzbarrierpiecestate( chunk, "opening" ); + } + } +} + +zombie_boardtear_offset_fx_horizontle( chunk, node ) //checked changed to match cerberus output +{ + if ( isDefined( chunk.script_parameters ) && chunk.script_parameters == "repair_board" || isDefined( chunk.script_parameters ) && chunk.script_parameters == "board" ) + { + if ( isDefined( chunk.unbroken ) && chunk.unbroken == 1 ) + { + if ( isDefined( chunk.material ) && chunk.material == "glass" ) + { + playfx( level._effect[ "glass_break" ], chunk.origin, node.angles ); + chunk.unbroken = 0; + } + else if ( isDefined( chunk.material ) && chunk.material == "metal" ) + { + playfx( level._effect[ "fx_zombie_bar_break" ], chunk.origin ); + chunk.unbroken = 0; + } + else if ( isDefined( chunk.material ) && chunk.material == "rock" ) + { + if ( is_true( level.use_clientside_rock_tearin_fx ) ) + { + chunk setclientflag( level._zombie_scriptmover_flag_rock_fx ); + } + else + { + playfx( level._effect[ "wall_break" ], chunk.origin ); + } + chunk.unbroken = 0; + } + } + } + if ( isDefined( chunk.script_parameters ) && chunk.script_parameters == "barricade_vents" ) + { + if ( is_true( level.use_clientside_board_fx ) ) + { + chunk setclientflag( level._zombie_scriptmover_flag_board_horizontal_fx ); + } + else + { + playfx( level._effect[ "fx_zombie_bar_break" ], chunk.origin ); + } + } + else if ( isDefined( chunk.material ) && chunk.material == "rock" ) + { + if ( is_true( level.use_clientside_rock_tearin_fx ) ) + { + chunk setclientflag( level._zombie_scriptmover_flag_rock_fx ); + } + } + else if ( isDefined( level.use_clientside_board_fx ) ) + { + chunk setclientflag( level._zombie_scriptmover_flag_board_horizontal_fx ); + } + else + { + playfx( level._effect[ "wood_chunk_destory" ], chunk.origin + vectorScale( ( 0, 0, 1 ), 30 ) ); + wait randomfloatrange( 0.2, 0.4 ); + playfx( level._effect[ "wood_chunk_destory" ], chunk.origin + vectorScale( ( 0, 0, -1 ), 30 ) ); + } +} + +zombie_boardtear_offset_fx_verticle( chunk, node ) //checked changed to match cerberus output +{ + if ( ( chunk.script_parameters == "repair_board" || chunk.script_parameters == "board" ) && isDefined( chunk.script_parameters ) ) + { + if ( isDefined( chunk.unbroken ) && chunk.unbroken == 1 ) + { + if ( isDefined( chunk.material ) && chunk.material == "glass" ) + { + playfx( level._effect[ "glass_break" ], chunk.origin, node.angles ); + chunk.unbroken = 0; + } + else if ( isDefined( chunk.material ) && chunk.material == "metal" ) + { + playfx( level._effect[ "fx_zombie_bar_break" ], chunk.origin ); + chunk.unbroken = 0; + } + else if ( isDefined( chunk.material ) && chunk.material == "rock" ) + { + if ( is_true( level.use_clientside_rock_tearin_fx ) ) + { + chunk setclientflag( level._zombie_scriptmover_flag_rock_fx ); + } + else + { + playfx( level._effect[ "wall_break" ], chunk.origin ); + } + chunk.unbroken = 0; + } + } + } + if ( isDefined( chunk.script_parameters ) && chunk.script_parameters == "barricade_vents" ) + { + if ( isDefined( level.use_clientside_board_fx ) ) + { + chunk setclientflag( level._zombie_scriptmover_flag_board_vertical_fx ); + } + else + { + playfx( level._effect[ "fx_zombie_bar_break" ], chunk.origin ); + } + } + else if ( isDefined( chunk.material ) && chunk.material == "rock" ) + { + if ( is_true( level.use_clientside_rock_tearin_fx ) ) + { + chunk setclientflag( level._zombie_scriptmover_flag_rock_fx ); + } + return; + } + else if ( isDefined( level.use_clientside_board_fx ) ) + { + chunk setclientflag( level._zombie_scriptmover_flag_board_vertical_fx ); + return; + } + else + { + playfx( level._effect[ "wood_chunk_destory" ], chunk.origin + vectorScale( ( 1, 0, 0 ), 30 ) ); + wait randomfloatrange( 0.2, 0.4 ); + playfx( level._effect[ "wood_chunk_destory" ], chunk.origin + vectorScale( ( -1, 0, 0 ), 30 ) ); + } +} + +zombie_bartear_offset_fx_verticle( chunk ) //checked changed to match cerberus output +{ + if ( ( chunk.script_parameters == "bar" || chunk.script_noteworthy == "board" ) && isDefined( chunk.script_parameters ) ) + { + possible_tag_array_1 = []; + possible_tag_array_1[ 0 ] = "Tag_fx_top"; + possible_tag_array_1[ 1 ] = ""; + possible_tag_array_1[ 2 ] = "Tag_fx_top"; + possible_tag_array_1[ 3 ] = ""; + possible_tag_array_2 = []; + possible_tag_array_2[ 0 ] = ""; + possible_tag_array_2[ 1 ] = "Tag_fx_bottom"; + possible_tag_array_2[ 2 ] = ""; + possible_tag_array_2[ 3 ] = "Tag_fx_bottom"; + possible_tag_array_2 = array_randomize( possible_tag_array_2 ); + random_fx = []; + random_fx[ 0 ] = level._effect[ "fx_zombie_bar_break" ]; + random_fx[ 1 ] = level._effect[ "fx_zombie_bar_break_lite" ]; + random_fx[ 2 ] = level._effect[ "fx_zombie_bar_break" ]; + random_fx[ 3 ] = level._effect[ "fx_zombie_bar_break_lite" ]; + random_fx = array_randomize( random_fx ); + switch( randomint( 9 ) ) + { + case 0: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_top" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_bottom" ); + break; + case 1: + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_top" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_bottom" ); + break; + case 2: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_top" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_bottom" ); + break; + case 3: + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_top" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_bottom" ); + break; + case 4: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_top" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_bottom" ); + break; + case 5: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_top" ); + break; + case 6: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_bottom" ); + break; + case 7: + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_top" ); + break; + case 8: + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_bottom" ); + break; + } + } +} + +zombie_bartear_offset_fx_horizontle( chunk ) //checked changed to match cerberus output +{ + if ( isDefined( chunk.script_parameters ) && chunk.script_parameters == "bar" || chunk.script_noteworthy == "board" ) + { + switch( randomint( 10 ) ) + { + case 0: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_left" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_right" ); + break; + case 1: + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_left" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_right" ); + break; + case 2: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_left" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_right" ); + break; + case 3: + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_left" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_right" ); + break; + case 4: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_left" ); + wait randomfloatrange( 0, 0.3 ); + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_right" ); + break; + case 5: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_left" ); + break; + case 6: + playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_right" ); + break; + case 7: + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_right" ); + break; + case 8: + playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_right" ); + break; + } + } +} + +check_zbarrier_piece_for_zombie_inert( chunk_index, zbarrier, zombie ) //checked matches cerberus output +{ + zombie endon( "completed_emerging_into_playable_area" ); + zombie waittill( "stop_zombie_goto_entrance" ); + if ( zbarrier getzbarrierpiecestate( chunk_index ) == "targetted_by_zombie" ) + { + zbarrier setzbarrierpiecestate( chunk_index, "closed" ); + } +} + +check_zbarrier_piece_for_zombie_death( chunk_index, zbarrier, zombie ) //checked matches cerberus output +{ + while ( 1 ) + { + if ( zbarrier getzbarrierpiecestate( chunk_index ) != "targetted_by_zombie" ) + { + return; + } + if ( !isDefined( zombie ) || !isalive( zombie ) ) + { + zbarrier setzbarrierpiecestate( chunk_index, "closed" ); + return; + } + wait 0.05; + } +} + +check_for_zombie_death( zombie ) //checked matches cerberus output +{ + self endon( "destroyed" ); + wait 2.5; + self maps/mp/zombies/_zm_blockers::update_states( "repaired" ); +} + +zombie_hat_gib( attacker, means_of_death ) //checked matches cerberus output +{ + self endon( "death" ); + if ( !is_mature() ) + { + return 0; + } + if ( is_true( self.hat_gibbed ) ) + { + return; + } + if ( !isDefined( self.gibspawn5 ) || !isDefined( self.gibspawntag5 ) ) + { + return; + } + self.hat_gibbed = 1; + if ( isDefined( self.hatmodel ) ) + { + self detach( self.hatmodel, "" ); + } + temp_array = []; + temp_array[ 0 ] = level._zombie_gib_piece_index_hat; + self gib( "normal", temp_array ); + if ( isDefined( level.track_gibs ) ) + { + level [[ level.track_gibs ]]( self, temp_array ); + } +} + +zombie_head_gib( attacker, means_of_death ) //checked changed to match cerberus output +{ + self endon( "death" ); + if ( !is_mature() ) + { + return 0; + } + if ( is_true( self.head_gibbed ) ) + { + return; + } + self.head_gibbed = 1; + self zombie_eye_glow_stop(); + size = self getattachsize(); + for ( i = 0; i < size; i++ ) + { + model = self getattachmodelname( i ); + if ( issubstr( model, "head" ) ) + { + if ( isDefined( self.hatmodel ) ) + { + self detach( self.hatmodel, "" ); + } + self detach( model, "" ); + if ( isDefined( self.torsodmg5 ) ) + { + self attach( self.torsodmg5, "", 1 ); + } + break; + } + } + temp_array = []; + temp_array[ 0 ] = level._zombie_gib_piece_index_head; + if ( !is_true( self.hat_gibbed ) && isDefined( self.gibspawn5 ) && isDefined( self.gibspawntag5 ) ) + { + temp_array[ 1 ] = level._zombie_gib_piece_index_hat; + } + self.hat_gibbed = 1; + self gib( "normal", temp_array ); + if ( isDefined( level.track_gibs ) ) + { + level [[ level.track_gibs ]]( self, temp_array ); + } + self thread damage_over_time( ceil( self.health * 0.2 ), 1, attacker, means_of_death ); +} + +damage_over_time( dmg, delay, attacker, means_of_death ) //checked matches cerberus output +{ + self endon( "death" ); + self endon( "exploding" ); + if ( !isalive( self ) ) + { + return; + } + if ( !isplayer( attacker ) ) + { + attacker = self; + } + if ( !isDefined( means_of_death ) ) + { + means_of_death = "MOD_UNKNOWN"; + } + while ( 1 ) + { + if ( isDefined( delay ) ) + { + wait delay; + } + if ( isDefined( self ) ) + { + self dodamage( dmg, self gettagorigin( "j_neck" ), attacker, self, self.damagelocation, means_of_death, 0, self.damageweapon ); + } + } +} + +head_should_gib( attacker, type, point ) //checked changed to match cerberus output +{ + if ( !is_mature() ) + { + return 0; + } + if ( self.head_gibbed ) + { + return 0; + } + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + return 0; + } + weapon = attacker getcurrentweapon(); + if ( type != "MOD_RIFLE_BULLET" && type != "MOD_PISTOL_BULLET" ) + { + if ( type == "MOD_GRENADE" || type == "MOD_GRENADE_SPLASH" ) + { + if ( distance( point, self gettagorigin( "j_head" ) ) > 55 ) + { + return 0; + } + else + { + return 1; + } + } + else if ( type == "MOD_PROJECTILE" ) + { + if ( distance( point, self gettagorigin( "j_head" ) ) > 10 ) + { + return 0; + } + else + { + return 1; + } + } + else if ( weaponclass( weapon ) != "spread" ) + { + return 0; + } + } + if ( !self maps/mp/animscripts/zm_utility::damagelocationisany( "head", "helmet", "neck" ) ) + { + return 0; + } + if ( weapon == "none" || weapon == level.start_weapon || weaponisgasweapon( self.weapon ) ) + { + return 0; + } + low_health_percent = ( self.health / self.maxhealth ) * 100; + if ( low_health_percent > 10 ) + { + self zombie_hat_gib( attacker, type ); + return 0; + } + return 1; +} + +headshot_blood_fx() //checked matches cerberus output +{ + if ( !isDefined( self ) ) + { + return; + } + if ( !is_mature() ) + { + return; + } + fxtag = "j_neck"; + fxorigin = self gettagorigin( fxtag ); + upvec = anglesToUp( self gettagangles( fxtag ) ); + forwardvec = anglesToForward( self gettagangles( fxtag ) ); + playfx( level._effect[ "headshot" ], fxorigin, forwardvec, upvec ); + playfx( level._effect[ "headshot_nochunks" ], fxorigin, forwardvec, upvec ); + wait 0.3; + if ( isDefined( self ) ) + { + playfxontag( level._effect[ "bloodspurt" ], self, fxtag ); + } +} + +zombie_gib_on_damage() //checked changed to match cerberus output +{ + + while ( 1 ) + { + self waittill( "damage", amount, attacker, direction_vec, point, type, tagname, modelname, partname, weaponname ); + if ( !isDefined( self ) ) + { + return; + } + if ( !self zombie_should_gib( amount, attacker, type ) ) + { + continue; + } + if ( self head_should_gib( attacker, type, point ) && type != "MOD_BURNED" ) + { + self zombie_head_gib( attacker, type ); + continue; //added from cerberus output + } + if ( !self.gibbed ) + { + if ( self maps/mp/animscripts/zm_utility::damagelocationisany( "head", "helmet", "neck" ) ) + { + continue; + } + refs = []; + switch( self.damagelocation ) + { + case "torso_lower": + case "torso_upper": + refs[ refs.size ] = "guts"; + refs[ refs.size ] = "right_arm"; + break; + case "right_arm_lower": + case "right_arm_upper": + case "right_hand": + refs[ refs.size ] = "right_arm"; + break; + case "left_arm_lower": + case "left_arm_upper": + case "left_hand": + refs[ refs.size ] = "left_arm"; + break; + case "right_foot": + case "right_leg_lower": + case "right_leg_upper": + if ( self.health <= 0 ) + { + refs[ refs.size ] = "right_leg"; + refs[ refs.size ] = "right_leg"; + refs[ refs.size ] = "right_leg"; + refs[ refs.size ] = "no_legs"; + } + break; + case "left_foot": + case "left_leg_lower": + case "left_leg_upper": + if ( self.health <= 0 ) + { + refs[ refs.size ] = "left_leg"; + refs[ refs.size ] = "left_leg"; + refs[ refs.size ] = "left_leg"; + refs[ refs.size ] = "no_legs"; + } + break; + default: + if ( self.damagelocation == "none" ) + { + if ( type != "MOD_GRENADE" && type != "MOD_GRENADE_SPLASH" || type == "MOD_PROJECTILE" && type == "MOD_PROJECTILE_SPLASH" ) + { + refs = self derive_damage_refs( point ); + break; + } + } + else + { + refs[ refs.size ] = "guts"; + refs[ refs.size ] = "right_arm"; + refs[ refs.size ] = "left_arm"; + refs[ refs.size ] = "right_leg"; + refs[ refs.size ] = "left_leg"; + refs[ refs.size ] = "no_legs"; + break; + } + } + } + if ( isDefined( level.custom_derive_damage_refs ) ) + { + refs = self [[ level.custom_derive_damage_refs ]]( refs, point, weaponname ); + } + if ( refs.size ) + { + self.a.gib_ref = maps/mp/animscripts/zm_death::get_random( refs ); + if ( self.a.gib_ref == "no_legs" && self.health > 0 || self.a.gib_ref == "right_leg" && self.health > 0 || self.a.gib_ref == "left_leg" && self.health > 0 ) + { + self.has_legs = 0; + self allowedstances( "crouch" ); + self setphysparams( 15, 0, 24 ); + self allowpitchangle( 1 ); + self setpitchorient(); + health = self.health; + health *= 0.1; + self thread maps/mp/animscripts/zm_run::needsdelayedupdate(); + if ( isDefined( self.crawl_anim_override ) ) + { + self [[ self.crawl_anim_override ]](); + } + } + } + if ( self.health > 0 ) + { + self thread maps/mp/animscripts/zm_death::do_gib(); + if ( isDefined( level.gib_on_damage ) ) + { + self thread [[ level.gib_on_damage ]](); + } + } + } +} + +zombie_should_gib( amount, attacker, type ) //checked changed to match cerberus output +{ + if ( !is_mature() ) + { + return 0; + } + if ( !isDefined( type ) ) + { + return 0; + } + if ( is_true( self.is_on_fire ) ) + { + return 0; + } + if ( isDefined( self.no_gib ) && self.no_gib == 1 ) + { + return 0; + } + switch( type ) + { + case "MOD_BURNED": + case "MOD_CRUSH": + case "MOD_FALLING": + case "MOD_SUICIDE": + case "MOD_TELEFRAG": + case "MOD_TRIGGER_HURT": + case "MOD_UNKNOWN": + return 0; + case "MOD_MELEE": + return 0; + } + if ( type == "MOD_PISTOL_BULLET" || type == "MOD_RIFLE_BULLET" ) + { + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + return 0; + } + weapon = attacker getcurrentweapon(); + if ( weapon == "none" || weapon == level.start_weapon ) + { + return 0; + } + if ( weaponisgasweapon( self.weapon ) ) + { + return 0; + } + } + else if ( type == "MOD_PROJECTILE" ) + { + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + weapon = attacker getcurrentweapon(); + if ( weapon == "slipgun_zm" || weapon == "slipgun_upgraded_zm" ) + { + return 0; + } + } + } + prev_health = amount + self.health; + if ( prev_health <= 0 ) + { + prev_health = 1; + } + damage_percent = ( amount / prev_health ) * 100; + if ( damage_percent < 10 ) + { + return 0; + } + return 1; +} + +derive_damage_refs( point ) //checked changed to match cerberus output +{ + if ( !isDefined( level.gib_tags ) ) + { + init_gib_tags(); + } + closesttag = undefined; + i = 0; + while ( i < level.gib_tags.size ) + { + if ( !isDefined( closesttag ) ) + { + closesttag = level.gib_tags[ i ]; + i++; + continue; + } + if ( distancesquared( point, self gettagorigin( level.gib_tags[ i ] ) ) < distancesquared( point, self gettagorigin( closesttag ) ) ) + { + closesttag = level.gib_tags[ i ]; + } + i++; + } + refs = []; + if ( closesttag != "J_SpineLower" || closesttag == "J_SpineUpper" || closesttag == "J_Spine4" ) + { + refs[ refs.size ] = "guts"; + refs[ refs.size ] = "right_arm"; + } + else if ( closesttag != "J_Shoulder_LE" || closesttag == "J_Elbow_LE" && closesttag == "J_Wrist_LE" ) + { + refs[ refs.size ] = "left_arm"; + } + else if ( closesttag != "J_Shoulder_RI" || closesttag == "J_Elbow_RI" && closesttag == "J_Wrist_RI" ) + { + refs[ refs.size ] = "right_arm"; + } + else if ( closesttag != "J_Hip_LE" || closesttag == "J_Knee_LE" && closesttag == "J_Ankle_LE" ) + { + refs[ refs.size ] = "left_leg"; + refs[ refs.size ] = "no_legs"; + } + else if ( closesttag != "J_Hip_RI" || closesttag == "J_Knee_RI" && closesttag == "J_Ankle_RI" ) + { + refs[ refs.size ] = "right_leg"; + refs[ refs.size ] = "no_legs"; + } + /* +/# + assert( array_validate( refs ), "get_closest_damage_refs(): couldn't derive refs from closestTag " + closesttag ); +#/ + */ + return refs; +} + +init_gib_tags() //checked matches cerberus output +{ + tags = []; + tags[ tags.size ] = "J_SpineLower"; + tags[ tags.size ] = "J_SpineUpper"; + tags[ tags.size ] = "J_Spine4"; + tags[ tags.size ] = "J_Shoulder_LE"; + tags[ tags.size ] = "J_Elbow_LE"; + tags[ tags.size ] = "J_Wrist_LE"; + tags[ tags.size ] = "J_Shoulder_RI"; + tags[ tags.size ] = "J_Elbow_RI"; + tags[ tags.size ] = "J_Wrist_RI"; + tags[ tags.size ] = "J_Hip_LE"; + tags[ tags.size ] = "J_Knee_LE"; + tags[ tags.size ] = "J_Ankle_LE"; + tags[ tags.size ] = "J_Hip_RI"; + tags[ tags.size ] = "J_Knee_RI"; + tags[ tags.size ] = "J_Ankle_RI"; + level.gib_tags = tags; +} + +zombie_can_drop_powerups( zombie ) //checked matches cerberus output +{ + if ( is_tactical_grenade( zombie.damageweapon ) || !flag( "zombie_drop_powerups" ) ) + { + return 0; + } + if ( is_true( zombie.no_powerups ) ) + { + return 0; + } + return 1; +} + +zombie_delay_powerup_drop( origin ) //checked matches cerberus output +{ + wait_network_frame(); + level thread maps/mp/zombies/_zm_powerups::powerup_drop( origin ); +} + +zombie_death_points( origin, mod, hit_location, attacker, zombie, team ) //checked matches cerberus output +{ + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + return; + } + if ( zombie_can_drop_powerups( zombie ) ) + { + if ( isDefined( zombie.in_the_ground ) && zombie.in_the_ground == 1 ) + { + trace = bullettrace( zombie.origin + vectorScale( ( 0, 0, 1 ), 100 ), zombie.origin + vectorScale( ( 0, 0, 0 ), -100 ), 0, undefined ); + origin = trace[ "position" ]; + level thread zombie_delay_powerup_drop( origin ); + } + else + { + trace = groundtrace( zombie.origin + vectorScale( ( 0, 0, 1 ), 5 ), zombie.origin + vectorScale( ( 0, 0, 0 ), -300 ), 0, undefined ); + origin = trace[ "position" ]; + level thread zombie_delay_powerup_drop( origin ); + } + } + level thread maps/mp/zombies/_zm_audio::player_zombie_kill_vox( hit_location, attacker, mod, zombie ); + event = "death"; + if ( isDefined( zombie.damageweapon ) && issubstr( zombie.damageweapon, "knife_ballistic_" ) || mod == "MOD_MELEE" && mod == "MOD_IMPACT" ) + { + event = "ballistic_knife_death"; + } + if ( is_true( zombie.deathpoints_already_given ) ) + { + return; + } + zombie.deathpoints_already_given = 1; + if ( isDefined( zombie.damageweapon ) && is_equipment( zombie.damageweapon ) ) + { + return; + } + attacker maps/mp/zombies/_zm_score::player_add_points( event, mod, hit_location, undefined, team, attacker.currentweapon ); +} + +get_number_variants( aliasprefix ) //checked matches cerberus output +{ + for ( i = 0; i < 100; i++ ) + { + if ( !soundexists( aliasprefix + "_" + i ) ) + { + return i; + } + } +} + +dragons_breath_flame_death_fx() //checked matches cerberus output +{ + if ( self.isdog ) + { + return; + } + if ( !isDefined( level._effect ) || !isDefined( level._effect[ "character_fire_death_sm" ] ) ) + { + /* +/# + println( "^3ANIMSCRIPT WARNING: You are missing level._effect["character_fire_death_sm"], please set it in your levelname_fx.gsc. Use "env/fire/fx_fire_zombie_md"" ); +#/ + */ + return; + } + playfxontag( level._effect[ "character_fire_death_sm" ], self, "J_SpineLower" ); + tagarray = []; + if ( !isDefined( self.a.gib_ref ) || self.a.gib_ref != "left_arm" ) + { + tagarray[ tagarray.size ] = "J_Elbow_LE"; + tagarray[ tagarray.size ] = "J_Wrist_LE"; + } + if ( !isDefined( self.a.gib_ref ) || self.a.gib_ref != "right_arm" ) + { + tagarray[ tagarray.size ] = "J_Elbow_RI"; + tagarray[ tagarray.size ] = "J_Wrist_RI"; + } + if ( !isDefined( self.a.gib_ref ) || self.a.gib_ref != "no_legs" && self.a.gib_ref != "left_leg" ) + { + tagarray[ tagarray.size ] = "J_Knee_LE"; + tagarray[ tagarray.size ] = "J_Ankle_LE"; + } + if ( !isDefined( self.a.gib_ref ) || self.a.gib_ref != "no_legs" && self.a.gib_ref != "right_leg" ) + { + tagarray[ tagarray.size ] = "J_Knee_RI"; + tagarray[ tagarray.size ] = "J_Ankle_RI"; + } + tagarray = array_randomize( tagarray ); + playfxontag( level._effect[ "character_fire_death_sm" ], self, tagarray[ 0 ] ); +} + +zombie_ragdoll_then_explode( launchvector, attacker ) //checked changed to match cerberus output +{ + if ( !isDefined( self ) ) + { + return; + } + self zombie_eye_glow_stop(); + self setclientfield( "zombie_ragdoll_explode", 1 ); + self notify( "exploding" ); + self notify( "end_melee" ); + self notify( "death", attacker ); + self.dont_die_on_me = 1; + self.exploding = 1; + self.a.nodeath = 1; + self.dont_throw_gib = 1; + self startragdoll(); + self setplayercollision( 0 ); + self reset_attack_spot(); + if ( isDefined( launchvector ) ) + { + self launchragdoll( launchvector ); + } + wait 2.1; + if ( isDefined( self ) ) + { + self ghost(); + self delay_thread( 0.25, ::self_delete ); + } +} + +zombie_death_animscript() //checked changed to match cerberus output +{ + team = undefined; + recalc_zombie_array(); + if ( isDefined( self._race_team ) ) + { + team = self._race_team; + } + self reset_attack_spot(); + if ( self check_zombie_death_animscript_callbacks() ) + { + return 0; + } + if ( isDefined( level.zombie_death_animscript_override ) ) + { + self [[ level.zombie_death_animscript_override ]](); + } + if ( self.has_legs && isDefined( self.a.gib_ref ) && self.a.gib_ref == "no_legs" ) + { + self.deathanim = "zm_death"; + } + self.grenadeammo = 0; + if ( isDefined( self.nuked ) ) + { + if ( zombie_can_drop_powerups( self ) ) + { + if ( isDefined( self.in_the_ground ) && self.in_the_ground == 1 ) + { + trace = bullettrace( self.origin + vectorScale( ( 0, 0, 1 ), 100 ), self.origin + vectorScale( ( 0, 0, 0 ), -100 ), 0, undefined ); + origin = trace[ "position" ]; + level thread zombie_delay_powerup_drop( origin ); + } + else + { + trace = groundtrace( self.origin + vectorScale( ( 0, 0, 1 ), 5 ), self.origin + vectorScale( ( 0, 0, 0 ), -300 ), 0, undefined ); + origin = trace[ "position" ]; + level thread zombie_delay_powerup_drop( self.origin ); + } + } + } + else + { + level zombie_death_points( self.origin, self.damagemod, self.damagelocation, self.attacker, self, team ); + } + if ( isDefined( self.attacker ) && isai( self.attacker ) ) + { + self.attacker notify( "killed", self ); + } + if ( self.damageweapon == "rottweil72_upgraded_zm" && self.damagemod == "MOD_RIFLE_BULLET" ) + { + self thread dragons_breath_flame_death_fx(); + } + if ( self.damageweapon == "tazer_knuckles_zm" && self.damagemod == "MOD_MELEE" ) + { + self.is_on_fire = 0; + self notify( "stop_flame_damage" ); + } + if ( self.damagemod == "MOD_BURNED" ) + { + self thread maps/mp/animscripts/zm_death::flame_death_fx(); + } + if ( self.damagemod == "MOD_GRENADE" || self.damagemod == "MOD_GRENADE_SPLASH" ) + { + level notify( "zombie_grenade_death", self.origin ); + } + return 0; +} + +check_zombie_death_animscript_callbacks() //checked changed to match cerberus output +{ + if ( !isDefined( level.zombie_death_animscript_callbacks ) ) + { + return 0; + } + for ( i = 0; i < level.zombie_death_animscript_callbacks.size; i++ ) + { + if ( self [[ level.zombie_death_animscript_callbacks[ i ] ]]() ) + { + return 1; + } + } + return 0; +} + +register_zombie_death_animscript_callback( func ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_death_animscript_callbacks ) ) + { + level.zombie_death_animscript_callbacks = []; + } + level.zombie_death_animscript_callbacks[ level.zombie_death_animscript_callbacks.size ] = func; +} + +damage_on_fire( player ) //checked matches cerberus output +{ + self endon( "death" ); + self endon( "stop_flame_damage" ); + wait 2; + while ( is_true( self.is_on_fire ) ) + { + if ( level.round_number < 6 ) + { + dmg = level.zombie_health * randomfloatrange( 0.2, 0.3 ); + } + else if ( level.round_number < 9 ) + { + dmg = level.zombie_health * randomfloatrange( 0.15, 0.25 ); + } + else if ( level.round_number < 11 ) + { + dmg = level.zombie_health * randomfloatrange( 0.1, 0.2 ); + } + else + { + dmg = level.zombie_health * randomfloatrange( 0.1, 0.15 ); + } + if ( isDefined( player ) && isalive( player ) ) + { + self dodamage( dmg, self.origin, player ); + } + else + { + self dodamage( dmg, self.origin, level ); + } + wait randomfloatrange( 1, 3 ); + } +} + +player_using_hi_score_weapon( player ) //checked matches cerberus output +{ + weapon = player getcurrentweapon(); + if ( weapon == "none" || weaponissemiauto( weapon ) ) + { + return 1; + } + return 0; +} + +zombie_damage( mod, hit_location, hit_origin, player, amount, team ) //checked changed to match cerberus output +{ + if ( is_magic_bullet_shield_enabled( self ) ) + { + return; + } + player.use_weapon_type = mod; + if ( isDefined( self.marked_for_death ) ) + { + return; + } + if ( !isDefined( player ) ) + { + return; + } + if ( isDefined( hit_origin ) ) + { + self.damagehit_origin = hit_origin; + } + else + { + self.damagehit_origin = player getweaponmuzzlepoint(); + } + if ( self check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount ) ) + { + return; + } + else if ( self zombie_flame_damage( mod, player ) ) + { + if ( self zombie_give_flame_damage_points() ) + { + player maps/mp/zombies/_zm_score::player_add_points( "damage", mod, hit_location, self.isdog, team ); + } + } + else if ( player_using_hi_score_weapon( player ) ) + { + damage_type = "damage"; + } + else + { + damage_type = "damage_light"; + } + if ( !is_true( self.no_damage_points ) ) + { + player maps/mp/zombies/_zm_score::player_add_points( damage_type, mod, hit_location, self.isdog, team, self.damageweapon ); + } + if ( isDefined( self.zombie_damage_fx_func ) ) + { + self [[ self.zombie_damage_fx_func ]]( mod, hit_location, hit_origin, player ); + } + modname = remove_mod_from_methodofdeath( mod ); + if ( is_placeable_mine( self.damageweapon ) ) + { + if ( isDefined( self.zombie_damage_claymore_func ) ) + { + self [[ self.zombie_damage_claymore_func ]]( mod, hit_location, hit_origin, player ); + } + else if ( isDefined( player ) && isalive( player ) ) + { + self dodamage( level.round_number * randomintrange( 100, 200 ), self.origin, player, self, hit_location, mod ); + } + else + { + self dodamage( level.round_number * randomintrange( 100, 200 ), self.origin, undefined, self, hit_location, mod ); + } + } + else if ( mod == "MOD_GRENADE" || mod == "MOD_GRENADE_SPLASH" ) + { + if ( isDefined( player ) && isalive( player ) ) + { + player.grenade_multiattack_count++; + player.grenade_multiattack_ent = self; + self dodamage( level.round_number + randomintrange( 100, 200 ), self.origin, player, self, hit_location, modname ); + } + else + { + self dodamage( level.round_number + randomintrange( 100, 200 ), self.origin, undefined, self, hit_location, modname ); + } + } + else if ( mod != "MOD_PROJECTILE" || mod == "MOD_EXPLOSIVE" && mod == "MOD_PROJECTILE_SPLASH" ) + { + if ( isDefined( player ) && isalive( player ) ) + { + self dodamage( level.round_number * randomintrange( 0, 100 ), self.origin, player, self, hit_location, modname ); + } + else + { + self dodamage( level.round_number * randomintrange( 0, 100 ), self.origin, undefined, self, hit_location, modname ); + } + } + if ( isDefined( self.a.gib_ref ) && self.a.gib_ref == "no_legs" && isalive( self ) ) + { + if ( isDefined( player ) ) + { + rand = randomintrange( 0, 100 ); + if ( rand < 10 ) + { + player create_and_play_dialog( "general", "crawl_spawn" ); + } + } + } + else if ( isDefined( self.a.gib_ref ) || self.a.gib_ref == "right_arm" && self.a.gib_ref == "left_arm" ) + { + if ( self.has_legs && isalive( self ) ) + { + if ( isDefined( player ) ) + { + rand = randomintrange( 0, 100 ); + if ( rand < 7 ) + { + player create_and_play_dialog( "general", "shoot_arm" ); + } + } + } + } + self thread maps/mp/zombies/_zm_powerups::check_for_instakill( player, mod, hit_location ); +} + +zombie_damage_ads( mod, hit_location, hit_origin, player, amount, team ) //checked changed to match cerberus output +{ + if ( is_magic_bullet_shield_enabled( self ) ) + { + return; + } + player.use_weapon_type = mod; + if ( !isDefined( player ) ) + { + return; + } + if ( isDefined( hit_origin ) ) + { + self.damagehit_origin = hit_origin; + } + else + { + self.damagehit_origin = player getweaponmuzzlepoint(); + } + if ( self check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount ) ) + { + return; + } + else if ( self zombie_flame_damage( mod, player ) ) + { + if ( self zombie_give_flame_damage_points() ) + { + player maps/mp/zombies/_zm_score::player_add_points( "damage_ads", mod, hit_location, undefined, team ); + } + } + else if ( player_using_hi_score_weapon( player ) ) + { + damage_type = "damage"; + } + else + { + damage_type = "damage_light"; + } + if ( !is_true( self.no_damage_points ) ) + { + player maps/mp/zombies/_zm_score::player_add_points( damage_type, mod, hit_location, undefined, team, self.damageweapon ); + } + self thread maps/mp/zombies/_zm_powerups::check_for_instakill( player, mod, hit_location ); +} + +check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount ) //checked changed to match cerberus output +{ + if ( !isDefined( level.zombie_damage_callbacks ) ) + { + return 0; + } + for ( i = 0; i < level.zombie_damage_callbacks.size; i++ ) + { + if ( self [[ level.zombie_damage_callbacks[ i ] ]]( mod, hit_location, hit_origin, player, amount ) ) + { + return 1; + } + } + return 0; +} + +register_zombie_damage_callback( func ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_damage_callbacks ) ) + { + level.zombie_damage_callbacks = []; + } + level.zombie_damage_callbacks[ level.zombie_damage_callbacks.size ] = func; +} + +zombie_give_flame_damage_points() //checked matches cerberus output +{ + if ( getTime() > self.flame_damage_time ) + { + self.flame_damage_time = getTime() + level.zombie_vars[ "zombie_flame_dmg_point_delay" ]; + return 1; + } + return 0; +} + +zombie_flame_damage( mod, player ) //checked changed to match cerberus output +{ + if ( mod == "MOD_BURNED" ) + { + if ( !is_true( self.is_on_fire ) ) + { + self thread damage_on_fire( player ); + } + do_flame_death = 1; + dist = 10000; + ai = getaiarray( level.zombie_team ); + for ( i = 0; i < ai.size; i++ ) + { + if ( is_true( ai[ i ].is_on_fire ) ) + { + if ( distancesquared( ai[ i ].origin, self.origin ) < dist ) + { + do_flame_death = 0; + break; + } + } + } + if ( do_flame_death ) + { + self thread maps/mp/animscripts/zm_death::flame_death_fx(); + } + return 1; + } + return 0; +} + +is_weapon_shotgun( sweapon ) //checked matches cerberus output +{ + if ( isDefined( sweapon ) && weaponclass( sweapon ) == "spread" ) + { + return 1; + } + return 0; +} + +zombie_death_event( zombie ) //checked changed to match cerberus output +{ + zombie.marked_for_recycle = 0; + force_explode = 0; + force_head_gib = 0; + zombie waittill( "death", attacker ); + time_of_death = getTime(); + if ( isDefined( zombie ) ) + { + zombie stopsounds(); + } + if ( isDefined( zombie ) && isDefined( zombie.marked_for_insta_upgraded_death ) ) + { + force_head_gib = 1; + } + if ( !isDefined( zombie.damagehit_origin ) && isDefined( attacker ) ) + { + zombie.damagehit_origin = attacker getweaponmuzzlepoint(); + } + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + if ( is_true( level.pers_upgrade_carpenter ) ) + { + maps/mp/zombies/_zm_pers_upgrades::pers_zombie_death_location_check( attacker, zombie.origin ); + } + if ( is_true( level.pers_upgrade_sniper ) ) + { + attacker pers_upgrade_sniper_kill_check( zombie, attacker ); + } + if ( isDefined( zombie ) && isDefined( zombie.damagelocation ) ) + { + if ( is_headshot( zombie.damageweapon, zombie.damagelocation, zombie.damagemod ) ) + { + attacker.headshots++; + attacker maps/mp/zombies/_zm_stats::increment_client_stat( "headshots" ); + attacker addweaponstat( zombie.damageweapon, "headshots", 1 ); + attacker maps/mp/zombies/_zm_stats::increment_player_stat( "headshots" ); + if ( is_classic() ) + { + attacker maps/mp/zombies/_zm_pers_upgrades_functions::pers_check_for_pers_headshot( time_of_death, zombie ); + } + } + else + { + attacker notify( "zombie_death_no_headshot" ); + } + } + if ( isDefined( zombie ) && isDefined( zombie.damagemod ) && zombie.damagemod == "MOD_MELEE" ) + { + attacker maps/mp/zombies/_zm_stats::increment_client_stat( "melee_kills" ); + attacker maps/mp/zombies/_zm_stats::increment_player_stat( "melee_kills" ); + attacker notify( "melee_kill" ); + if ( attacker maps/mp/zombies/_zm_pers_upgrades::is_insta_kill_upgraded_and_active() ) + { + force_explode = 1; + } + } + attacker maps/mp/zombies/_zm::add_rampage_bookmark_kill_time(); + attacker.kills++; + attacker maps/mp/zombies/_zm_stats::increment_client_stat( "kills" ); + attacker maps/mp/zombies/_zm_stats::increment_player_stat( "kills" ); + if ( is_true( level.pers_upgrade_pistol_points ) ) + { + attacker maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_pistol_points_kill(); + } + dmgweapon = zombie.damageweapon; + if ( is_alt_weapon( dmgweapon ) ) + { + dmgweapon = weaponaltweaponname( dmgweapon ); + } + attacker addweaponstat( dmgweapon, "kills", 1 ); + if ( attacker maps/mp/zombies/_zm_pers_upgrades_functions::pers_mulit_kill_headshot_active() || force_head_gib ) + { + zombie maps/mp/zombies/_zm_spawner::zombie_head_gib(); + } + if ( is_true( level.pers_upgrade_nube ) ) + { + attacker notify( "pers_player_zombie_kill" ); + } + } + zombie_death_achievement_sliquifier_check( attacker, zombie ); + recalc_zombie_array(); + if ( !isDefined( zombie ) ) + { + return; + } + level.global_zombies_killed++; + if ( isDefined( zombie.marked_for_death ) && !isDefined( zombie.nuked ) ) + { + level.zombie_trap_killed_count++; + } + zombie check_zombie_death_event_callbacks(); + name = zombie.animname; + if ( isDefined( zombie.sndname ) ) + { + name = zombie.sndname; + } + zombie thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "death", name ); + zombie thread zombie_eye_glow_stop(); + if ( isDefined( zombie.damageweapon ) && is_weapon_shotgun( zombie.damageweapon ) && !maps/mp/zombies/_zm_weapons::is_weapon_upgraded( zombie.damageweapon ) || isDefined( zombie.damageweapon ) && is_placeable_mine( zombie.damageweapon ) || zombie.damagemod == "MOD_GRENADE" || zombie.damagemod == "MOD_GRENADE_SPLASH" || zombie.damagemod == "MOD_EXPLOSIVE" || force_explode == 1 ) + { + splode_dist = 180; + if ( isDefined( zombie.damagehit_origin ) && distancesquared( zombie.origin, zombie.damagehit_origin ) < ( splode_dist * splode_dist ) ) + { + tag = "J_SpineLower"; + if ( is_true( zombie.isdog ) ) + { + tag = "tag_origin"; + } + if ( !is_true( zombie.is_on_fire ) && !is_true( zombie.guts_explosion ) ) + { + zombie thread zombie_gut_explosion(); + } + } + } + if ( zombie.damagemod == "MOD_GRENADE" || zombie.damagemod == "MOD_GRENADE_SPLASH" ) + { + if ( isDefined( attacker ) && isalive( attacker ) ) + { + attacker.grenade_multiattack_count++; + attacker.grenade_multiattack_ent = zombie; + } + } + if ( !is_true( zombie.has_been_damaged_by_player ) && is_true( zombie.marked_for_recycle ) ) + { + level.zombie_total++; + level.zombie_total_subtract++; + } + else if ( isDefined( zombie.attacker ) && isplayer( zombie.attacker ) ) + { + level.zombie_player_killed_count++; + if ( isDefined( zombie.sound_damage_player ) && zombie.sound_damage_player == zombie.attacker ) + { + chance = get_response_chance( "damage" ); + if ( chance != 0 ) + { + if ( chance > randomintrange( 1, 100 ) ) + { + zombie.attacker maps/mp/zombies/_zm_audio::create_and_play_dialog( "kill", "damage" ); + } + } + else + { + zombie.attacker maps/mp/zombies/_zm_audio::create_and_play_dialog( "kill", "damage" ); + } + } + zombie.attacker notify( "zom_kill", zombie ); + damageloc = zombie.damagelocation; + damagemod = zombie.damagemod; + attacker = zombie.attacker; + weapon = zombie.damageweapon; + bbprint( "zombie_kills", "round %d zombietype %s damagetype %s damagelocation %s playername %s playerweapon %s playerx %f playery %f playerz %f zombiex %f zombiey %f zombiez %f", level.round_number, zombie.animname, damagemod, damageloc, attacker.name, weapon, attacker.origin, zombie.origin ); + } + else if ( zombie.ignoreall && !is_true( zombie.marked_for_death ) ) + { + level.zombies_timeout_spawn++; + } + level notify( "zom_kill" ); + level.total_zombies_killed++; +} + +zombie_gut_explosion() //checked matches cerberus output +{ + self.guts_explosion = 1; + if ( is_mature() ) + { + self setclientfield( "zombie_gut_explosion", 1 ); + } + if ( !is_true( self.isdog ) ) + { + wait 0.1; + } + if ( isDefined( self ) ) + { + self ghost(); + } +} + +zombie_death_achievement_sliquifier_check( e_player, e_zombie ) //checked matches cerberus output +{ + if ( !isplayer( e_player ) ) + { + return; + } + if ( isDefined( e_zombie ) ) + { + if ( isDefined( e_zombie.damageweapon ) && e_zombie.damageweapon == "slipgun_zm" ) + { + if ( !isDefined( e_player.num_sliquifier_kills ) ) + { + e_player.num_sliquifier_kills = 0; + } + e_player.num_sliquifier_kills++; + e_player notify( "sliquifier_kill" ); + } + } +} + +check_zombie_death_event_callbacks() //checked changed to match cerberus output +{ + if ( !isDefined( level.zombie_death_event_callbacks ) ) + { + return; + } + for ( i = 0; i < level.zombie_death_event_callbacks.size; i++ ) + { + self [[ level.zombie_death_event_callbacks[ i ] ]](); + } +} + +register_zombie_death_event_callback( func ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_death_event_callbacks ) ) + { + level.zombie_death_event_callbacks = []; + } + level.zombie_death_event_callbacks[ level.zombie_death_event_callbacks.size ] = func; +} + +deregister_zombie_death_event_callback( func ) //checked matches cerberus output +{ + if ( isDefined( level.zombie_death_event_callbacks ) ) + { + arrayremovevalue( level.zombie_death_event_callbacks, func ); + } +} + +zombie_setup_attack_properties() //checked matches cerberus output +{ + self zombie_history( "zombie_setup_attack_properties()" ); + self.ignoreall = 0; + self.pathenemyfightdist = 64; + self.meleeattackdist = 64; + self.maxsightdistsqrd = 16384; + self.disablearrivals = 1; + self.disableexits = 1; +} + +attractors_generated_listener() //checked matches cerberus output +{ + self endon( "death" ); + level endon( "intermission" ); + self endon( "stop_find_flesh" ); + self endon( "path_timer_done" ); + level waittill( "attractor_positions_generated" ); + self.zombie_path_timer = 0; +} + +zombie_pathing() //checked changed to match cerberus output +{ + self endon( "death" ); + self endon( "zombie_acquire_enemy" ); + level endon( "intermission" ); + /* +/# + if ( !isDefined( self.favoriteenemy ) ) + { + assert( isDefined( self.enemyoverride ) ); + } +#/ + */ + self._skip_pathing_first_delay = 1; + self thread zombie_follow_enemy(); + self waittill( "bad_path" ); + level.zombie_pathing_failed++; + if ( isDefined( self.enemyoverride ) ) + { + //debug_print( "Zombie couldn't path to point of interest at origin: " + self.enemyoverride[ 0 ] + " Falling back to breadcrumb system" ); + if ( isDefined( self.enemyoverride[ 1 ] ) ) + { + self.enemyoverride = self.enemyoverride[ 1 ] invalidate_attractor_pos( self.enemyoverride, self ); + self.zombie_path_timer = 0; + return; + } + } + else if ( isDefined( self.favoriteenemy ) ) + { + //debug_print( "Zombie couldn't path to player at origin: " + self.favoriteenemy.origin + " Falling back to breadcrumb system" ); + } + else + { + //debug_print( "Zombie couldn't path to a player ( the other 'prefered' player might be ignored for encounters mode ). Falling back to breadcrumb system" ); + } + if ( !isDefined( self.favoriteenemy ) ) + { + self.zombie_path_timer = 0; + return; + } + else + { + self.favoriteenemy endon( "disconnect" ); + } + players = get_players(); + valid_player_num = 0; + for ( i = 0; i < players.size; i++ ) + { + if ( is_player_valid( players[ i ], 1 ) ) + { + valid_player_num += 1; + } + } + if ( players.size > 1 ) + { + if ( isDefined( level._should_skip_ignore_player_logic ) && [[ level._should_skip_ignore_player_logic ]]() ) + { + self.zombie_path_timer = 0; + return; + } + if ( array_check_for_dupes( self.ignore_player, self.favoriteenemy ) ) + { + self.ignore_player[ self.ignore_player.size ] = self.favoriteenemy; + } + if ( self.ignore_player.size < valid_player_num ) + { + self.zombie_path_timer = 0; + return; + } + } + crumb_list = self.favoriteenemy.zombie_breadcrumbs; + bad_crumbs = []; + while ( 1 ) + { + if ( !is_player_valid( self.favoriteenemy, 1 ) ) + { + self.zombie_path_timer = 0; + return; + } + goal = zombie_pathing_get_breadcrumb( self.favoriteenemy.origin, crumb_list, bad_crumbs, randomint( 100 ) < 20 ); + if ( !isDefined( goal ) ) + { + //debug_print( "Zombie exhausted breadcrumb search" ); + level.zombie_breadcrumb_failed++; + goal = self.favoriteenemy.spectator_respawn.origin; + } + //debug_print( "Setting current breadcrumb to " + goal ); + self.zombie_path_timer += 100; + self setgoalpos( goal ); + self waittill( "bad_path" ); + //debug_print( "Zombie couldn't path to breadcrumb at " + goal + " Finding next breadcrumb" ); + for ( i = 0; i < crumb_list.size; i++ ) + { + if ( goal == crumb_list[ i ] ) + { + bad_crumbs[ bad_crumbs.size ] = i; + break; + } + } + } +} + +zombie_pathing_get_breadcrumb( origin, breadcrumbs, bad_crumbs, pick_random ) //checked changed to match cerberus output +{ +/* +/# + assert( isDefined( origin ) ); +#/ +/# + assert( isDefined( breadcrumbs ) ); +#/ +/# + assert( isarray( breadcrumbs ) ); +#/ +/# + if ( pick_random ) + { + debug_print( "Finding random breadcrumb" ); +#/ + } +*/ + i = 0; + while ( i < breadcrumbs.size ) + { + if ( pick_random ) + { + crumb_index = randomint( breadcrumbs.size ); + } + else + { + crumb_index = i; + } + if ( crumb_is_bad( crumb_index, bad_crumbs ) ) + { + i++; + continue; + } + i++; + return breadcrumbs[ crumb_index ]; + } + return undefined; +} + +crumb_is_bad( crumb, bad_crumbs ) //checked changed to match cerberus output +{ + for ( i = 0; i < bad_crumbs.size; i++ ) + { + if ( bad_crumbs[ i ] == crumb ) + { + return 1; + } + } + return 0; +} + +jitter_enemies_bad_breadcrumbs( start_crumb ) //checked changed to match cerberus output +{ + trace_distance = 35; + jitter_distance = 2; + index = start_crumb; + while ( isDefined( self.favoriteenemy.zombie_breadcrumbs[ index + 1 ] ) ) + { + current_crumb = self.favoriteenemy.zombie_breadcrumbs[ index ]; + next_crumb = self.favoriteenemy.zombie_breadcrumbs[ index + 1 ]; + angles = vectorToAngles( current_crumb - next_crumb ); + right = anglesToRight( angles ); + left = anglesToRight( angles + vectorScale( ( 0, 1, 0 ), 180 ) ); + dist_pos = current_crumb + vectorScale( right, trace_distance ); + trace = bullettrace( current_crumb, dist_pos, 1, undefined ); + vector = trace[ "position" ]; + if ( distance( vector, current_crumb ) < 17 ) + { + self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + vectorScale( left, jitter_distance ); + continue; + } + dist_pos = current_crumb + vectorScale( left, trace_distance ); + trace = bullettrace( current_crumb, dist_pos, 1, undefined ); + vector = trace[ "position" ]; + if ( distance( vector, current_crumb ) < 17 ) + { + self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + vectorScale( right, jitter_distance ); + continue; + } + index++; + } +} + +zombie_repath_notifier() //checked changed to match cerberus output +{ + note = 0; + notes = []; + for ( i = 0; i < 4; i++ ) + { + notes[ notes.size ] = "zombie_repath_notify_" + i; + } + while ( 1 ) + { + level notify( notes[ note ] ); + note = ( note + 1 ) % 4; + wait 0.05; + } +} + +zombie_follow_enemy() //checked changed to match cerberus output +{ + self endon( "death" ); + self endon( "zombie_acquire_enemy" ); + self endon( "bad_path" ); + level endon( "intermission" ); + if ( !isDefined( level.repathnotifierstarted ) ) + { + level.repathnotifierstarted = 1; + level thread zombie_repath_notifier(); + } + if ( !isDefined( self.zombie_repath_notify ) ) + { + self.zombie_repath_notify = "zombie_repath_notify_" + self getentitynumber() % 4; + } + while ( 1 ) + { + if ( !isDefined( self._skip_pathing_first_delay ) ) + { + level waittill( self.zombie_repath_notify ); + } + else + { + self._skip_pathing_first_delay = undefined; + } + if ( !is_true( self.ignore_enemyoverride ) && isDefined( self.enemyoverride ) && isDefined( self.enemyoverride[ 1 ] ) ) + { + if ( distancesquared( self.origin, self.enemyoverride[ 0 ] ) > 1 ) + { + self orientmode( "face motion" ); + } + else + { + self orientmode( "face point", self.enemyoverride[ 1 ].origin ); + } + self.ignoreall = 1; + goalpos = self.enemyoverride[ 0 ]; + if ( isDefined( level.adjust_enemyoverride_func ) ) + { + goalpos = self [[ level.adjust_enemyoverride_func ]](); + } + self setgoalpos( goalpos ); + } + else if ( isDefined( self.favoriteenemy ) ) + { + self.ignoreall = 0; + self orientmode( "face default" ); + goalpos = self.favoriteenemy.origin; + if ( isDefined( level.enemy_location_override_func ) ) + { + goalpos = [[ level.enemy_location_override_func ]]( self, self.favoriteenemy ); + } + self setgoalpos( goalpos ); + if ( !isDefined( level.ignore_path_delays ) ) + { + distsq = distancesquared( self.origin, self.favoriteenemy.origin ); + if ( distsq > 10240000 ) + { + wait ( 2 + randomfloat( 1 ) ); + } + else if ( distsq > 4840000 ) + { + wait ( 1 + randomfloat( 0.5 ) ); + } + else if ( distsq > 1440000 ) + { + wait ( 0.5 + randomfloat( 0.5 ) ); + } + } + } + if ( isDefined( level.inaccesible_player_func ) ) + { + self [[ level.inaccessible_player_func ]](); + } + } +} + +zombie_eye_glow() //checked matches cerberus output +{ + if ( !isDefined( self ) ) + { + return; + } + if ( !is_true( self.no_eye_glow ) ) + { + self setclientfield( "zombie_has_eyes", 1 ); + } +} + +zombie_eye_glow_stop() //checked matches cerberus output +{ + if ( !isDefined( self ) ) + { + return; + } + if ( !is_true( self.no_eye_glow ) ) + { + self setclientfield( "zombie_has_eyes", 0 ); + } +} + +zombie_history( msg ) //dev call did not check +{ +/* +/# + if ( !isDefined( self.zombie_history ) || self.zombie_history.size > 32 ) + { + self.zombie_history = []; + } + self.zombie_history[ self.zombie_history.size ] = msg; +#/ +*/ +} + +do_zombie_spawn() //checked changed to match cerberus output +{ + self endon( "death" ); + spots = []; + if ( isDefined( self._rise_spot ) ) + { + spot = self._rise_spot; + self thread do_zombie_rise( spot ); + return; + } + if ( isDefined( level.zombie_spawn_locations ) ) + { + i = 0; + while ( i < level.zombie_spawn_locations.size ) + { + if ( is_true( level.use_multiple_spawns ) && isDefined( self.script_int ) ) + { + if ( isDefined( level.spawner_int ) && self.script_int == level.spawner_int && ( !isDefined( level.zombie_spawn_locations[ i ].script_int ) || !isDefined( level.zones[ level.zombie_spawn_locations[ i ].zone_name ].script_int ) ) ) + { + i++; + continue; + } + if ( isDefined( level.zombie_spawn_locations[ i ].script_int ) && level.zombie_spawn_locations[ i ].script_int != self.script_int ) + { + i++; + continue; + } + if ( isDefined( level.zones[ level.zombie_spawn_locations[ i ].zone_name ].script_int ) && level.zones[ level.zombie_spawn_locations[ i ].zone_name ].script_int != self.script_int ) + { + i++; + continue; + } + } + spots[ spots.size ] = level.zombie_spawn_locations[ i ]; + i++; + } + } + /* +/# + if ( getDvarInt( #"A8C231AA" ) ) + { + if ( isDefined( level.zombie_spawn_locations ) ) + { + player = get_players()[ 0 ]; + spots = []; + i = 0; + while ( i < level.zombie_spawn_locations.size ) + { + player_vec = vectornormalize( anglesToForward( player.angles ) ); + player_spawn = vectornormalize( level.zombie_spawn_locations[ i ].origin - player.origin ); + dot = vectordot( player_vec, player_spawn ); + if ( dot > 0,707 ) + { + spots[ spots.size ] = level.zombie_spawn_locations[ i ]; + debugstar( level.zombie_spawn_locations[ i ].origin, 1000, ( 0, 0, 0 ) ); + } + i++; + } + if ( spots.size <= 0 ) + { + spots[ spots.size ] = level.zombie_spawn_locations[ 0 ]; + iprintln( "no spawner in view" ); +#/ + } + } + } + */ + /* +/# + assert( spots.size > 0, "No spawn locations found" ); +#/ + */ + spot = random( spots ); + self.spawn_point = spot; + /* +/# + if ( is_true( level.toggle_show_spawn_locations ) ) + { + debugstar( spot.origin, getDvarInt( #"BB9101B2" ), ( 0, 0, 0 ) ); + host_player = gethostplayer(); + distance = distance( spot.origin, host_player.origin ); + iprintln( "Distance to player: " + ( distance / 12 ) + "feet" ); +#/ + } + */ + if ( isDefined( spot.target ) ) + { + self.target = spot.target; + } + if ( isDefined( spot.zone_name ) ) + { + self.zone_name = spot.zone_name; + } + if ( isDefined( spot.script_parameters ) ) + { + self.script_parameters = spot.script_parameters; + } + tokens = strtok( spot.script_noteworthy, " " ); + i = 0; + while ( i < tokens.size ) + { + if ( isdefined( self.spawn_point_override ) ) + { + spot = self.spawn_point_override; + tokens[ i ] = spot.script_noteworthy; + } + if ( tokens[ i ] == "custom_spawner_entry" ) + { + if ( isdefined( tokens[ i ] ) ) + { + str_spawn_entry = tokens[ i ]; + if ( isdefined( level.custom_spawner_entry ) && isdefined( level.custom_spawner_entry[ str_spawn_entry ] ) ) + { + self thread [[ level.custom_spawner_entry[ str_spawn_entry ] ]](spot); + i++; + continue; + } + } + } + if ( tokens[ i ] == "riser_location" ) + { + self thread do_zombie_rise( spot ); + i++; + continue; + } + if ( tokens[ i ] == "faller_location" ) + { + self thread maps/mp/zombies/_zm_ai_faller::do_zombie_fall( spot ); + i++; + continue; + } + if ( tokens[ i ] == "dog_location" ) + { + i++; + continue; + } + if ( tokens[ i ] == "screecher_location" ) + { + i++; + continue; + } + if ( tokens[ i ] == "leaper_location" ) + { + i++; + continue; + } + if ( isdefined(self.anchor ) ) + { + i++; + return; + } + self.anchor = spawn( "script_origin", self.origin ); + self.anchor.angles = self.angles; + self linkto( self.anchor ); + if ( !isDefined( spot.angles ) ) + { + spot.angles = ( 0, 0, 0 ); + } + self ghost(); + self.anchor moveto( spot.origin, 0.05 ); + self.anchor waittill( "movedone" ); + target_org = get_desired_origin(); + if ( isDefined( target_org ) ) + { + anim_ang = vectorToAngles( target_org - self.origin ); + self.anchor rotateto( ( 0, anim_ang[ 1 ], 0 ), 0.05 ); + self.anchor waittill( "rotatedone" ); + } + if ( isDefined( level.zombie_spawn_fx ) ) + { + playfx( level.zombie_spawn_fx, spot.origin ); + } + self unlink(); + if ( isDefined( self.anchor ) ) + { + self.anchor delete(); + } + self show(); + self notify( "risen", spot.script_string ); + i++; + } +} + +do_zombie_rise( spot ) //checked changed to match cerberus output +{ + self endon( "death" ); + self.in_the_ground = 1; + if ( isDefined( self.anchor ) ) + { + self.anchor delete(); + } + self.anchor = spawn( "script_origin", self.origin ); + self.anchor.angles = self.angles; + self linkto( self.anchor ); + if ( !isDefined( spot.angles ) ) + { + spot.angles = ( 0, 0, 0 ); + } + anim_org = spot.origin; + anim_ang = spot.angles; + anim_org += ( 0, 0, 0 ); + self ghost(); + self.anchor moveto( anim_org, 0.05 ); + self.anchor waittill( "movedone" ); + target_org = get_desired_origin(); + if ( isDefined( target_org ) ) + { + anim_ang = vectorToAngles( target_org - self.origin ); + self.anchor rotateto( ( 0, anim_ang[ 1 ], 0 ), 0.05 ); + self.anchor waittill( "rotatedone" ); + } + self unlink(); + if ( isDefined( self.anchor ) ) + { + self.anchor delete(); + } + self thread hide_pop(); + level thread zombie_rise_death( self, spot ); + spot thread zombie_rise_fx( self ); + substate = 0; + if ( self.zombie_move_speed == "walk" ) + { + substate = randomint( 2 ); + } + else if ( self.zombie_move_speed == "run" ) + { + substate = 2; + } + else if ( self.zombie_move_speed == "sprint" ) + { + substate = 3; + } + self orientmode( "face default" ); + self animscripted( self.origin, spot.angles, "zm_rise", substate ); + self maps/mp/animscripts/zm_shared::donotetracks( "rise_anim", ::handle_rise_notetracks, spot ); + self notify( "rise_anim_finished" ); + spot notify( "stop_zombie_rise_fx" ); + self.in_the_ground = 0; + self notify( "risen", spot.script_string ); +} + +hide_pop() //checked matches cerberus output +{ + self endon( "death" ); + wait 0.5; + if ( isDefined( self ) ) + { + self show(); + wait_network_frame(); + if ( isDefined( self ) ) + { + self.create_eyes = 1; + } + } +} + +handle_rise_notetracks( note, spot ) //checked matches cerberus output +{ + if ( note == "deathout" || note == "deathhigh" ) + { + self.zombie_rise_death_out = 1; + self notify( "zombie_rise_death_out" ); + wait 2; + spot notify( "stop_zombie_rise_fx" ); + } +} + +zombie_rise_death( zombie, spot ) //checked matches cerberus output +{ + zombie.zombie_rise_death_out = 0; + zombie endon( "rise_anim_finished" ); + while ( isDefined( zombie ) && isDefined( zombie.health ) && zombie.health > 1 ) + { + zombie waittill( "damage", amount ); + } + spot notify( "stop_zombie_rise_fx" ); + if ( isDefined( zombie ) ) + { + zombie.deathanim = zombie get_rise_death_anim(); + zombie stopanimscripted(); + } +} + +zombie_rise_fx( zombie ) //checked matches cerberus output +{ + if ( !is_true( level.riser_fx_on_client ) ) + { + self thread zombie_rise_dust_fx( zombie ); + self thread zombie_rise_burst_fx( zombie ); + } + else + { + self thread zombie_rise_burst_fx( zombie ); + } + zombie endon( "death" ); + self endon( "stop_zombie_rise_fx" ); + wait 1; + if ( zombie.zombie_move_speed != "sprint" ) + { + wait 1; + } +} + +zombie_rise_burst_fx( zombie ) //checked changed to match cerberus output +{ + self endon( "stop_zombie_rise_fx" ); + self endon( "rise_anim_finished" ); + if ( isDefined( self.script_parameters ) && self.script_parameters == "in_water" && !is_true( level._no_water_risers ) ) + { + zombie setclientfield( "zombie_riser_fx_water", 1 ); + } + else if ( isDefined( self.script_parameters ) && self.script_parameters == "in_foliage" && is_true( level._foliage_risers ) ) + { + zombie setclientfield( "zombie_riser_fx_foliage", 1 ); + return; + } + else if ( isDefined( self.script_parameters ) && self.script_parameters == "in_snow" ) + { + zombie setclientfield( "zombie_riser_fx", 1 ); + return; + } + else if ( isDefined( zombie.zone_name ) && isDefined( level.zones[ zombie.zone_name ] ) ) + { + low_g_zones = getentarray( zombie.zone_name, "targetname" ); + if ( isDefined( low_g_zones[ 0 ].script_string ) && low_g_zones[ 0 ].script_string == "lowgravity" ) + { + zombie setclientfield( "zombie_riser_fx_lowg", 1 ); + } + else + { + zombie setclientfield( "zombie_riser_fx", 1 ); + } + } + else + { + zombie setclientfield( "zombie_riser_fx", 1 ); + } +} + +zombie_rise_dust_fx( zombie ) //checked does not match cerberus output did not change +{ + dust_tag = "J_SpineUpper"; + self endon( "stop_zombie_rise_dust_fx" ); + self thread stop_zombie_rise_dust_fx( zombie ); + wait 2; + dust_time = 5.5; + dust_interval = 0.3; + if ( isDefined( self.script_string ) && self.script_string == "in_water" ) + { + t = 0; + while ( t < dust_time ) + { + playfxontag( level._effect[ "rise_dust_water" ], zombie, dust_tag ); + wait dust_interval; + t += dust_interval; + } + } + if ( isDefined( self.script_string ) && self.script_string == "in_snow" ) + { + t = 0; + while ( t < dust_time ) + { + playfxontag( level._effect[ "rise_dust_snow" ], zombie, dust_tag ); + wait dust_interval; + t += dust_interval; + } + } + if ( isDefined( self.script_string ) && self.script_string == "in_foliage" ) + { + t = 0; + while ( t < dust_time ) + { + playfxontag( level._effect[ "rise_dust_foliage" ], zombie, dust_tag ); + wait dust_interval; + t += dust_interval; + } + } + while ( t < dust_time ) + { + playfxontag( level._effect[ "rise_dust" ], zombie, dust_tag ); + wait dust_interval; + t += dust_interval; + } +} + +stop_zombie_rise_dust_fx( zombie ) //checked matches cerberus output +{ + zombie waittill( "death" ); + self notify( "stop_zombie_rise_dust_fx" ); +} + +get_rise_death_anim() //checked matches cerberus output +{ + if ( self.zombie_rise_death_out ) + { + return "zm_rise_death_out"; + } + self.noragdoll = 1; + self.nodeathragdoll = 1; + return "zm_rise_death_in"; +} + +zombie_tesla_head_gib() //checked matches cerberus output +{ + self endon( "death" ); + if ( self.animname == "quad_zombie" ) + { + return; + } + if ( randomint( 100 ) < level.zombie_vars[ "tesla_head_gib_chance" ] ) + { + wait randomfloatrange( 0.53, 1 ); + self zombie_head_gib(); + } + else + { + network_safe_play_fx_on_tag( "tesla_death_fx", 2, level._effect[ "tesla_shock_eyes" ], self, "J_Eyeball_LE" ); + } +} + +play_ambient_zombie_vocals() //checked changed to match cerberus output +{ + self endon( "death" ); + if ( self.animname == "monkey_zombie" || isDefined( self.is_avogadro ) && self.is_avogadro ) + { + return; + } + while ( 1 ) + { + type = "ambient"; + float = 2; + while ( !isDefined( self.zombie_move_speed ) ) + { + wait 0.5; + } + switch( self.zombie_move_speed ) + { + case "walk": + type = "ambient"; + float = 4; + break; + case "run": + type = "sprint"; + float = 4; + break; + case "sprint": + type = "sprint"; + float = 4; + break; + } + if ( self.animname == "zombie" && !self.has_legs ) + { + type = "crawler"; + } + else if ( self.animname == "thief_zombie" || self.animname == "leaper_zombie" ) + { + float = 1.2; + } + name = self.animname; + if ( isDefined( self.sndname ) ) + { + name = self.sndname; + } + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( type, name ); + wait randomfloatrange( 1, float ); + } +} + +zombie_complete_emerging_into_playable_area() //checked matches cerberus output +{ + self.completed_emerging_into_playable_area = 1; + self notify( "completed_emerging_into_playable_area" ); + self.no_powerups = 0; + self thread zombie_free_cam_allowed(); +} + +zombie_free_cam_allowed() //checked matches cerberus output +{ + self endon( "death" ); + wait 1.5; + self setfreecameralockonallowed( 1 ); +} + + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_weapons.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_weapons.gsc new file mode 100644 index 0000000..6f62d73 --- /dev/null +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_weapons.gsc @@ -0,0 +1,2807 @@ +#include maps/mp/zombies/_zm_weap_cymbal_monkey; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_pers_upgrades_functions; +#include maps/mp/zombies/_zm_melee_weapon; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/gametypes_zm/_weapons; +#include maps/mp/gametypes_zm/_weaponobjects; +#include maps/mp/zombies/_zm_magicbox; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; +#include maps/mp/zombies/_zm_weap_claymore; +#include maps/mp/zombies/_zm_weap_ballistic_knife; + + +init() //checked matches cerberus output +{ + //begin debug + level.custom_zm_weapons_loaded = 1; + maps/mp/zombies/_zm_bot::init(); + if ( !isDefined( level.debugLogging_zm_weapons ) ) + { + level.debugLogging_zm_weapons = 0; + } + //end debug + init_weapons(); + init_weapon_upgrade(); + init_weapon_toggle(); + precacheshader( "minimap_icon_mystery_box" ); + precacheshader( "specialty_instakill_zombies" ); + precacheshader( "specialty_firesale_zombies" ); + precacheitem( "zombie_fists_zm" ); + level._weaponobjects_on_player_connect_override = ::weaponobjects_on_player_connect_override; + level._zombiemode_check_firesale_loc_valid_func = ::default_check_firesale_loc_valid_func; + level.missileentities = []; + setupretrievablehintstrings(); + level thread onplayerconnect(); + +} + +setupretrievablehintstrings() //checked matches cerberus output +{ + maps/mp/gametypes_zm/_weaponobjects::createretrievablehint( "claymore", &"ZOMBIE_CLAYMORE_PICKUP" ); +} + +onplayerconnect() //checked matches cerberus output +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread onplayerspawned(); + } +} + +onplayerspawned() //checked matches cerberus output +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread watchforgrenadeduds(); + self thread watchforgrenadelauncherduds(); + self.staticweaponsstarttime = getTime(); + } +} + +watchforgrenadeduds() //checked matches cerberus output +{ + self endon( "spawned_player" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "grenade_fire", grenade, weapname ); + if ( !is_equipment( weapname ) && weapname != "claymore_zm" ) + { + grenade thread checkgrenadefordud( weapname, 1, self ); + grenade thread watchforscriptexplosion( weapname, 1, self ); + } + } +} + +watchforgrenadelauncherduds() //checked matches cerberus output +{ + self endon( "spawned_player" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "grenade_launcher_fire", grenade, weapname ); + grenade thread checkgrenadefordud( weapname, 0, self ); + grenade thread watchforscriptexplosion( weapname, 0, self ); + } +} + +grenade_safe_to_throw( player, weapname ) //checked matches cerberus output +{ + if ( isDefined( level.grenade_safe_to_throw ) ) + { + return self [[ level.grenade_safe_to_throw ]]( player, weapname ); + } + return 1; +} + +grenade_safe_to_bounce( player, weapname ) //checked matches cerberus output +{ + if ( isDefined( level.grenade_safe_to_bounce ) ) + { + return self [[ level.grenade_safe_to_bounce ]]( player, weapname ); + } + return 1; +} + +makegrenadedudanddestroy() //checked matches cerberus output +{ + self endon( "death" ); + self notify( "grenade_dud" ); + self makegrenadedud(); + wait 3; + if ( isDefined( self ) ) + { + self delete(); + } +} + +checkgrenadefordud( weapname, isthrowngrenade, player ) //checked matches cerberus output +{ + self endon( "death" ); + player endon( "zombify" ); + if ( !self grenade_safe_to_throw( player, weapname ) ) + { + self thread makegrenadedudanddestroy(); + return; + } + for ( ;; ) + { + self waittill_any_timeout( 0.25, "grenade_bounce", "stationary" ); + if ( !self grenade_safe_to_bounce( player, weapname ) ) + { + self thread makegrenadedudanddestroy(); + return; + } + } +} + +wait_explode() //checked matches cerberus output +{ + self endon( "grenade_dud" ); + self endon( "done" ); + self waittill( "explode", position ); + level.explode_position = position; + level.explode_position_valid = 1; + self notify( "done" ); +} + +wait_timeout( time ) //checked matches cerberus output +{ + self endon( "grenade_dud" ); + self endon( "done" ); + wait time; + self notify( "done" ); +} + +wait_for_explosion( time ) //checked changed to match cerberus output +{ + level.explode_position = ( 0, 0, 0 ); + level.explode_position_valid = 0; + self thread wait_explode(); + self thread wait_timeout( time ); + self waittill( "done" ); + self notify( "death_or_explode", level.explode_position_valid, level.explode_position ); +} + +watchforscriptexplosion( weapname, isthrowngrenade, player ) //checked changed to match cerberus output +{ + self endon( "grenade_dud" ); + if ( is_lethal_grenade( weapname ) || is_grenade_launcher( weapname ) ) + { + self thread wait_for_explosion( 20 ); + self waittill( "death_or_explode", exploded, position ); + if ( exploded ) + { + level notify( "grenade_exploded", position, 256, 300, 75 ); + } + } +} + +get_nonalternate_weapon( altweapon ) //checked changed to match cerberus output +{ + if ( is_alt_weapon( altweapon ) ) + { + alt = weaponaltweaponname( altweapon ); + if ( alt == "none" ) + { + primaryweapons = self getweaponslistprimaries(); + alt = primaryweapons[ 0 ]; + foreach ( weapon in primaryweapons ) + { + if ( weaponaltweaponname( weapon ) == altweapon ) + { + alt = weapon; + break; + } + } + } + return alt; + } + return altweapon; +} + +switch_from_alt_weapon( current_weapon ) //checked changed to match cerberus output +{ + if ( is_alt_weapon( current_weapon ) ) + { + alt = weaponaltweaponname( current_weapon ); + if ( alt == "none" ) + { + primaryweapons = self getweaponslistprimaries(); + alt = primaryweapons[ 0 ]; + foreach ( weapon in primaryweapons ) + { + if ( weaponaltweaponname( weapon ) == current_weapon ) + { + alt = weapon; + break; + } + } + } + self switchtoweaponimmediate( alt ); + self waittill_notify_or_timeout( "weapon_change_complete", 1 ); + return alt; + } + return current_weapon; +} + +give_fallback_weapon() //checked matches cerberus output +{ + self giveweapon( "zombie_fists_zm" ); + self switchtoweapon( "zombie_fists_zm" ); +} + +take_fallback_weapon() //checked matches cerberus output +{ + if ( self hasweapon( "zombie_fists_zm" ) ) + { + self takeweapon( "zombie_fists_zm" ); + } +} + +switch_back_primary_weapon( oldprimary ) //checked changed to match cerberus output +{ + if ( is_true( self.laststand ) ) + { + return; + } + primaryweapons = self getweaponslistprimaries(); + if ( isDefined( oldprimary ) && isinarray( primaryweapons, oldprimary ) ) + { + self switchtoweapon( oldprimary ); + } + else if ( isDefined( primaryweapons ) && primaryweapons.size > 0 ) + { + self switchtoweapon( primaryweapons[ 0 ] ); + } +} + +add_retrievable_knife_init_name( name ) //checked matches cerberus output +{ + if ( !isDefined( level.retrievable_knife_init_names ) ) + { + level.retrievable_knife_init_names = []; + } + level.retrievable_knife_init_names[ level.retrievable_knife_init_names.size ] = name; +} + +watchweaponusagezm() //checked changed to match cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + for ( ;; ) + { + self waittill( "weapon_fired", curweapon ); + self.lastfiretime = getTime(); + self.hasdonecombat = 1; + 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; + } + case "pistol": + case "pistol spread": + case "pistolspread": + case "mg": + case "smg": + case "spread": + self trackweaponfire( curweapon ); + level.globalshotsfired++; + break; + case "grenade": + case "rocketlauncher": + if ( is_alt_weapon( curweapon ) ) + { + curweapon = weaponaltweaponname( curweapon ); + } + self addweaponstat( curweapon, "shots", 1 ); + break; + default: + + switch( curweapon ) + { + case "m202_flash_mp": + case "m220_tow_mp": + case "m32_mp": + case "minigun_mp": + case "mp40_blinged_mp": + self.usedkillstreakweapon[ curweapon ] = 1; + break; + default: + + } + } + } +} + +trackweaponzm() //checked changed to match cerberus output +{ + self.currentweapon = self getcurrentweapon(); + self.currenttime = getTime(); + spawnid = getplayerspawnid( self ); + while ( 1 ) + { + event = self waittill_any_return( "weapon_change", "death", "disconnect", "bled_out" ); + newtime = getTime(); + if ( event == "weapon_change" ) + { + newweapon = self getcurrentweapon(); + if ( newweapon != "none" && newweapon != self.currentweapon ) + { + updatelastheldweapontimingszm( newtime ); + self.currentweapon = newweapon; + self.currenttime = newtime; + } + } + if ( event != "disconnect" ) + { + updateweapontimingszm( newtime ); + } + //return; //changed at own discretion + } +} + +updatelastheldweapontimingszm( newtime ) //checked matches cerberus output +{ + if ( isDefined( self.currentweapon ) && isDefined( self.currenttime ) ) + { + curweapon = self.currentweapon; + totaltime = int( ( newtime - self.currenttime ) / 1000 ); + if ( totaltime > 0 ) + { + if ( is_alt_weapon( curweapon ) ) + { + curweapon = weaponaltweaponname( curweapon ); + } + self addweaponstat( curweapon, "timeUsed", totaltime ); + } + } +} + +updateweapontimingszm( newtime ) //checked matches cerberus output +{ + if ( self is_bot() ) + { + return; + } + updatelastheldweapontimingszm( newtime ); + if ( !isDefined( self.staticweaponsstarttime ) ) + { + return; + } + totaltime = int( ( newtime - self.staticweaponsstarttime ) / 1000 ); + if ( totaltime < 0 ) + { + return; + } + self.staticweaponsstarttime = newtime; +} + +watchweaponchangezm() //checked matches cerberus output +{ + self endon( "death" ); + self endon( "disconnect" ); + self.lastdroppableweapon = self getcurrentweapon(); + self.hitsthismag = []; + weapon = self getcurrentweapon(); + if ( isDefined( weapon ) && weapon != "none" && !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 ( !isDefined( self.hitsthismag[ newweapon ] ) ) + { + self.hitsthismag[ newweapon ] = weaponclipsize( newweapon ); + } + } + } +} + +weaponobjects_on_player_connect_override_internal() //checked changed to match cerberus output +{ + self maps/mp/gametypes_zm/_weaponobjects::createbasewatchers(); + self createclaymorewatcher_zm(); + for ( i = 0; i < level.retrievable_knife_init_names.size; i++ ) + { + self createballisticknifewatcher_zm( level.retrievable_knife_init_names[ i ], level.retrievable_knife_init_names[ i ] + "_zm" ); + } + self maps/mp/gametypes_zm/_weaponobjects::setupretrievablewatcher(); + if ( !isDefined( self.weaponobjectwatcherarray ) ) + { + self.weaponobjectwatcherarray = []; + } + self thread maps/mp/gametypes_zm/_weaponobjects::watchweaponobjectspawn(); + self thread maps/mp/gametypes_zm/_weaponobjects::watchweaponprojectileobjectspawn(); + self thread maps/mp/gametypes_zm/_weaponobjects::deleteweaponobjectson(); + self.concussionendtime = 0; + self.hasdonecombat = 0; + self.lastfiretime = 0; + self thread watchweaponusagezm(); + self thread maps/mp/gametypes_zm/_weapons::watchgrenadeusage(); + self thread maps/mp/gametypes_zm/_weapons::watchmissileusage(); + self thread watchweaponchangezm(); + self thread maps/mp/gametypes_zm/_weapons::watchturretuse(); + self thread trackweaponzm(); + self notify( "weapon_watchers_created" ); +} + +weaponobjects_on_player_connect_override() //checked matches cerberus output +{ + add_retrievable_knife_init_name( "knife_ballistic" ); + add_retrievable_knife_init_name( "knife_ballistic_upgraded" ); + onplayerconnect_callback( ::weaponobjects_on_player_connect_override_internal ); +} + +createclaymorewatcher_zm() //checked changed to match cerberus output +{ + watcher = self maps/mp/gametypes_zm/_weaponobjects::createuseweaponobjectwatcher( "claymore", "claymore_zm", self.team ); + watcher.onspawnretrievetriggers = maps/mp/zombies/_zm_weap_claymore::on_spawn_retrieve_trigger; + watcher.adjusttriggerorigin = maps/mp/zombies/_zm_weap_claymore::adjust_trigger_origin; + watcher.pickup = level.pickup_claymores; + watcher.pickup_trigger_listener = level.pickup_claymores_trigger_listener; + watcher.skip_weapon_object_damage = 1; + watcher.headicon = 0; + watcher.watchforfire = 1; + watcher.detonate = ::claymoredetonate; + watcher.ondamage = level.claymores_on_damage; +} + +createballisticknifewatcher_zm( name, weapon ) //checked changed to match cerberus output +{ + watcher = self maps/mp/gametypes_zm/_weaponobjects::createuseweaponobjectwatcher( name, weapon, self.team ); + watcher.onspawn = maps/mp/zombies/_zm_weap_ballistic_knife::on_spawn; + watcher.onspawnretrievetriggers = maps/mp/zombies/_zm_weap_ballistic_knife::on_spawn_retrieve_trigger; + watcher.storedifferentobject = 1; + watcher.headicon = 0; +} + +isempweapon( weaponname ) //checked changed at own discretion +{ + if ( isDefined( weaponname ) && weaponname == "emp_grenade_zm" ) + { + return 1; + } + return 0; +} + +claymoredetonate( attacker, weaponname ) //checked matches cerberus output +{ + from_emp = isempweapon( weaponname ); + 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(); + } +} + +default_check_firesale_loc_valid_func() //checked matches cerberus output +{ + return 1; +} + +add_zombie_weapon( weapon_name, upgrade_name, hint, cost, weaponvo, weaponvoresp, ammo_cost, create_vox ) //checked matches cerberus output +{ + if ( isDefined( level.zombie_include_weapons ) && !isDefined( level.zombie_include_weapons[ weapon_name ] ) ) + { + return; + } + table = "mp/zombiemode.csv"; + table_cost = tablelookup( table, 0, weapon_name, 1 ); + table_ammo_cost = tablelookup( table, 0, weapon_name, 2 ); + if ( isDefined( table_cost ) && table_cost != "" ) + { + cost = round_up_to_ten( int( table_cost ) ); + } + if ( isDefined( table_ammo_cost ) && table_ammo_cost != "" ) + { + ammo_cost = round_up_to_ten( int( table_ammo_cost ) ); + } + precachestring( hint ); + struct = spawnstruct(); + if ( !isDefined( level.zombie_weapons ) ) + { + level.zombie_weapons = []; + } + if ( !isDefined( level.zombie_weapons_upgraded ) ) + { + level.zombie_weapons_upgraded = []; + } + if ( isDefined( upgrade_name ) ) + { + level.zombie_weapons_upgraded[ upgrade_name ] = weapon_name; + } + + struct.weapon_name = weapon_name; + struct.upgrade_name = upgrade_name; + struct.weapon_classname = "weapon_" + weapon_name; + struct.hint = hint; + struct.cost = cost; + struct.vox = weaponvo; + struct.vox_response = weaponvoresp; + struct.is_in_box = level.zombie_include_weapons[ weapon_name ]; + if ( !isDefined( ammo_cost ) ) + { + ammo_cost = round_up_to_ten( int( cost * 0.5 ) ); + } + struct.ammo_cost = ammo_cost; + + + level.zombie_weapons[ weapon_name ] = struct; + if ( is_true( level.zombiemode_reusing_pack_a_punch ) && isDefined( upgrade_name ) ) + { + add_attachments( weapon_name, upgrade_name ); + } + if ( isDefined( create_vox ) ) + { + level.vox maps/mp/zombies/_zm_audio::zmbvoxadd( "player", "weapon_pickup", weapon_name, weaponvo, undefined ); + } +} + +add_attachments( weapon_name, upgrade_name ) //checked does not match cerberus output did not change +{ + table = "zm/pap_attach.csv"; + if ( isDefined( level.weapon_attachment_table ) ) + { + table = level.weapon_attachment_table; + } + row = tablelookuprownum( table, 0, upgrade_name ); + if ( row > -1 ) + { + level.zombie_weapons[ weapon_name ].default_attachment = TableLookUp( table, 0, upgrade_name, 1 ); + level.zombie_weapons[ weapon_name ].addon_attachments = []; + index = 2; + next_addon = TableLookUp( table, 0, upgrade_name, index ); + + while ( isdefined( next_addon ) && next_addon.size > 0 ) + { + level.zombie_weapons[ weapon_name ].addon_attachments[ level.zombie_weapons[ weapon_name ].addon_attachments.size ] = next_addon; + index++; + next_addon = TableLookUp( table, 0, upgrade_name, index ); + } + } +} + +default_weighting_func() //checked matches cerberus output +{ + return 1; +} + +default_tesla_weighting_func() //checked changed to match cerberus output +{ + num_to_add = 1; + if ( isDefined( level.pulls_since_last_tesla_gun ) ) + { + if ( isDefined( level.player_drops_tesla_gun ) && level.player_drops_tesla_gun == 1 ) + { + num_to_add += int( 0.2 * level.zombie_include_weapons.size ); + } + if ( !isDefined( level.player_seen_tesla_gun ) || level.player_seen_tesla_gun == 0 ) + { + if ( level.round_number > 10 ) + { + num_to_add += int( 0.2 * level.zombie_include_weapons.size ); + } + else if ( level.round_number > 5 ) + { + num_to_add += int( 0.15 * level.zombie_include_weapons.size ); + } + } + } + return num_to_add; +} + +default_1st_move_weighting_func() //checked matches cerberus output +{ + if ( level.chest_moves > 0 ) + { + num_to_add = 1; + return num_to_add; + } + else + { + return 0; + } +} + +default_upgrade_weapon_weighting_func() //checked matches cerberus output +{ + if ( level.chest_moves > 1 ) + { + return 1; + } + else + { + return 0; + } +} + +default_cymbal_monkey_weighting_func() //checked changed to match cerberus output +{ + players = get_players(); + count = 0; + for ( i = 0; i < players.size; i++ ) + { + if ( players[ i ] has_weapon_or_upgrade( "cymbal_monkey_zm" ) ) + { + count++; + } + } + if ( count > 0 ) + { + return 1; + } + else if ( level.round_number < 10 ) + { + return 3; + } + else + { + return 5; + } +} + +is_weapon_included( weapon_name ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_weapons ) ) + { + return 0; + } + return isDefined( level.zombie_weapons[ weapon_name ] ); +} + +is_weapon_or_base_included( weapon_name ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_weapons ) ) + { + return 0; + } + if ( isDefined( level.zombie_weapons[ weapon_name ] ) ) + { + return 1; + } + base = get_base_weapon_name( weapon_name, 1 ); + if ( isDefined( level.zombie_weapons[ base ] ) ) + { + return 1; + } + return 0; +} + +include_zombie_weapon( weapon_name, in_box, collector, weighting_func ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_include_weapons ) ) + { + level.zombie_include_weapons = []; + } + if ( !isDefined( in_box ) ) + { + in_box = 1; + } + + level.zombie_include_weapons[ weapon_name ] = in_box; + precacheitem( weapon_name ); + if ( !isDefined( weighting_func ) ) + { + level.weapon_weighting_funcs[ weapon_name ] = ::default_weighting_func; + } + else + { + level.weapon_weighting_funcs[ weapon_name ] = weighting_func; + } +} + +init_weapons() //checked matches cerberus output +{ + if ( isdefined( level._zombie_custom_add_weapons ) ) + { + [[ level._zombie_custom_add_weapons ]](); + } + precachemodel( "zombie_teddybear" ); +} + +add_limited_weapon( weapon_name, amount ) //checked matches cerberus output +{ + if ( !isDefined( level.limited_weapons ) ) + { + level.limited_weapons = []; + } + level.limited_weapons[ weapon_name ] = amount; +} + +limited_weapon_below_quota( weapon, ignore_player, pap_triggers ) //checked changed to match cerberus output +{ + if ( isDefined( level.limited_weapons[ weapon ] ) ) + { + if ( !isDefined( pap_triggers ) ) + { + if ( !isDefined( level.pap_triggers ) ) + { + pap_triggers = getentarray( "specialty_weapupgrade", "script_noteworthy" ); + } + else + { + pap_triggers = level.pap_triggers; + } + } + if ( is_true( level.no_limited_weapons ) ) + { + return 0; + } + upgradedweapon = weapon; + if ( isDefined( level.zombie_weapons[ weapon ] ) && isDefined( level.zombie_weapons[ weapon ].upgrade_name ) ) + { + upgradedweapon = level.zombie_weapons[ weapon ].upgrade_name; + } + players = get_players(); + count = 0; + limit = level.limited_weapons[ weapon ]; + i = 0; + while ( i < players.size) + { + if ( isDefined( ignore_player ) && ignore_player == players[ i ] ) + { + i++; + continue; + } + if ( players[ i ] has_weapon_or_upgrade( weapon ) ) + { + count++; + if ( count >= limit ) + { + return 0; + } + } + i++; + } + for ( k = 0; k < pap_triggers.size; k++ ) + { + if ( isDefined( pap_triggers[ k ].current_weapon ) && pap_triggers[ k ].current_weapon == weapon || isDefined( pap_triggers[ k ].current_weapon ) && pap_triggers[ k ].current_weapon == upgradedweapon ) + { + count++; + if ( count >= limit ) + { + return 0; + } + } + } + for ( chestindex = 0; chestindex < level.chests.size; chestindex++ ) + { + if ( isDefined( level.chests[ chestindex ].zbarrier.weapon_string ) && level.chests[ chestindex ].zbarrier.weapon_string == weapon ) + { + count++; + if ( count >= limit ) + { + return 0; + } + } + } + if ( isDefined( level.custom_limited_weapon_checks ) ) + { + foreach ( check in level.custom_limited_weapon_checks ) + { + count = count + [[ check ]]( weapon ); + } + if ( count >= limit ) + { + return 0; + } + } + if ( isDefined( level.random_weapon_powerups ) ) + { + for ( powerupindex = 0; powerupindex < level.random_weapon_powerups.size; powerupindex++ ) + { + if ( isDefined( level.random_weapon_powerups[ powerupindex ] ) && level.random_weapon_powerups[ powerupindex ].base_weapon == weapon ) + { + count++; + if ( count >= limit ) + { + return 0; + } + } + } + } + } + return 1; +} + +add_custom_limited_weapon_check( callback ) //checked matches cerberus output +{ + if ( !isDefined( level.custom_limited_weapon_checks ) ) + { + level.custom_limited_weapon_checks = []; + } + level.custom_limited_weapon_checks[ level.custom_limited_weapon_checks.size ] = callback; +} + +add_weapon_to_content( weapon_name, package ) //checked matches cerberus output +{ + if ( !isDefined( level.content_weapons ) ) + { + level.content_weapons = []; + } + level.content_weapons[ weapon_name ] = package; +} + +player_can_use_content( weapon ) //checked matches cerberus output +{ + if ( isDefined( level.content_weapons ) ) + { + if ( isDefined( level.content_weapons[ weapon ] ) ) + { + return self hasdlcavailable( level.content_weapons[ weapon ] ); + } + } + return 1; +} + +init_spawnable_weapon_upgrade() //checked partially changed to match cerberus output +{ + spawn_list = []; + spawnable_weapon_spawns = getstructarray( "weapon_upgrade", "targetname" ); + spawnable_weapon_spawns = arraycombine( spawnable_weapon_spawns, getstructarray( "bowie_upgrade", "targetname" ), 1, 0 ); + spawnable_weapon_spawns = arraycombine( spawnable_weapon_spawns, getstructarray( "sickle_upgrade", "targetname" ), 1, 0 ); + spawnable_weapon_spawns = arraycombine( spawnable_weapon_spawns, getstructarray( "tazer_upgrade", "targetname" ), 1, 0 ); + spawnable_weapon_spawns = arraycombine( spawnable_weapon_spawns, getstructarray( "buildable_wallbuy", "targetname" ), 1, 0 ); + if ( !is_true( level.headshots_only ) ) + { + spawnable_weapon_spawns = arraycombine( spawnable_weapon_spawns, getstructarray( "claymore_purchase", "targetname" ), 1, 0 ); + } + 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; + if ( location != "" ) + { + match_string = match_string + "_" + location; + } + match_string_plus_space = " " + match_string; + i = 0; + while ( i < spawnable_weapon_spawns.size ) + { + spawnable_weapon = spawnable_weapon_spawns[ i ]; + if ( isDefined( spawnable_weapon.zombie_weapon_upgrade ) && spawnable_weapon.zombie_weapon_upgrade == "sticky_grenade_zm" && is_true( level.headshots_only ) ) + { + i++; + continue; + } + if ( !isDefined( spawnable_weapon.script_noteworthy ) || spawnable_weapon.script_noteworthy == "" ) + { + spawn_list[ spawn_list.size ] = spawnable_weapon; + i++; + continue; + } + matches = strtok( spawnable_weapon.script_noteworthy, "," ); + for ( j = 0; j < matches.size; j++ ) + { + if ( matches[ j ] == match_string || matches[ j ] == match_string_plus_space ) + { + spawn_list[ spawn_list.size ] = spawnable_weapon; + } + } + i++; + } + tempmodel = spawn( "script_model", ( 0, 0, 0 ) ); + i = 0; + while ( i < spawn_list.size ) + { + clientfieldname = spawn_list[ i ].zombie_weapon_upgrade + "_" + spawn_list[ i ].origin; + numbits = 2; + if ( isDefined( level._wallbuy_override_num_bits ) ) + { + numbits = level._wallbuy_override_num_bits; + } + registerclientfield( "world", clientfieldname, 1, numbits, "int" ); + target_struct = getstruct( spawn_list[ i ].target, "targetname" ); + if ( spawn_list[ i ].targetname == "buildable_wallbuy" ) + { + bits = 4; + if ( isDefined( level.buildable_wallbuy_weapons ) ) + { + bits = getminbitcountfornum( level.buildable_wallbuy_weapons.size + 1 ); + } + registerclientfield( "world", clientfieldname + "_idx", 12000, bits, "int" ); + spawn_list[ i ].clientfieldname = clientfieldname; + i++; + continue; + } + precachemodel( target_struct.model ); + unitrigger_stub = spawnstruct(); + unitrigger_stub.origin = spawn_list[ i ].origin; + unitrigger_stub.angles = spawn_list[ i ].angles; + tempmodel.origin = spawn_list[ i ].origin; + tempmodel.angles = spawn_list[ i ].angles; + mins = undefined; + maxs = undefined; + absmins = undefined; + absmaxs = undefined; + tempmodel setmodel( target_struct.model ); + tempmodel useweaponhidetags( spawn_list[ i ].zombie_weapon_upgrade ); + mins = tempmodel getmins(); + maxs = tempmodel getmaxs(); + absmins = tempmodel getabsmins(); + absmaxs = tempmodel getabsmaxs(); + bounds = absmaxs - absmins; + unitrigger_stub.script_length = bounds[ 0 ] * 0.25; + unitrigger_stub.script_width = bounds[ 1 ]; + unitrigger_stub.script_height = bounds[ 2 ]; + unitrigger_stub.origin -= anglesToRight( unitrigger_stub.angles ) * ( unitrigger_stub.script_length * 0.4 ); + unitrigger_stub.target = spawn_list[ i ].target; + unitrigger_stub.targetname = spawn_list[ i ].targetname; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + if ( spawn_list[ i ].targetname == "weapon_upgrade" ) + { + unitrigger_stub.cost = get_weapon_cost( spawn_list[ i ].zombie_weapon_upgrade ); + if ( !is_true( level.monolingustic_prompt_format ) ) + { + unitrigger_stub.hint_string = get_weapon_hint( spawn_list[ i ].zombie_weapon_upgrade ); + unitrigger_stub.hint_parm1 = unitrigger_stub.cost; + } + else + { + unitrigger_stub.hint_parm1 = get_weapon_display_name( spawn_list[ i ].zombie_weapon_upgrade ); + if ( !isDefined( unitrigger_stub.hint_parm1 ) || unitrigger_stub.hint_parm1 == "" || unitrigger_stub.hint_parm1 == "none" ) + { + unitrigger_stub.hint_parm1 = "missing weapon name " + spawn_list[ i ].zombie_weapon_upgrade; + } + unitrigger_stub.hint_parm2 = unitrigger_stub.cost; + unitrigger_stub.hint_string = &"ZOMBIE_WEAPONCOSTONLY"; + } + } + unitrigger_stub.weapon_upgrade = spawn_list[ i ].zombie_weapon_upgrade; + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + unitrigger_stub.require_look_at = 1; + if ( isDefined( spawn_list[ i ].require_look_from ) && spawn_list[ i ].require_look_from ) + { + unitrigger_stub.require_look_from = 1; + } + unitrigger_stub.zombie_weapon_upgrade = spawn_list[ i ].zombie_weapon_upgrade; + unitrigger_stub.clientfieldname = clientfieldname; + maps/mp/zombies/_zm_unitrigger::unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + if ( is_melee_weapon( unitrigger_stub.zombie_weapon_upgrade ) ) + { + if ( unitrigger_stub.zombie_weapon_upgrade == "tazer_knuckles_zm" && isDefined( level.taser_trig_adjustment ) ) + { + unitrigger_stub.origin += level.taser_trig_adjustment; + } + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::weapon_spawn_think ); + } + else if ( unitrigger_stub.zombie_weapon_upgrade == "claymore_zm" ) + { + unitrigger_stub.prompt_and_visibility_func = ::claymore_unitrigger_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::buy_claymores ); + } + else + { + unitrigger_stub.prompt_and_visibility_func = ::wall_weapon_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::weapon_spawn_think ); + } + spawn_list[ i ].trigger_stub = unitrigger_stub; + i++; + } + level._spawned_wallbuys = spawn_list; + tempmodel delete(); +} + +add_dynamic_wallbuy( weapon, wallbuy, pristine ) //checked partially changed to match cerberus output +{ + spawned_wallbuy = undefined; + for ( i = 0; i < level._spawned_wallbuys.size; i++ ) + { + if ( level._spawned_wallbuys[ i ].target == wallbuy ) + { + spawned_wallbuy = level._spawned_wallbuys[ i ]; + break; + } + } + if ( !isDefined( spawned_wallbuy ) ) + { + return; + } + if ( isDefined( spawned_wallbuy.trigger_stub ) ) + { + return; + } + target_struct = getstruct( wallbuy, "targetname" ); + wallmodel = spawn_weapon_model( weapon, undefined, target_struct.origin, target_struct.angles ); + clientfieldname = spawned_wallbuy.clientfieldname; + model = getweaponmodel( weapon ); + unitrigger_stub = spawnstruct(); + unitrigger_stub.origin = target_struct.origin; + unitrigger_stub.angles = target_struct.angles; + wallmodel.origin = target_struct.origin; + wallmodel.angles = target_struct.angles; + mins = undefined; + maxs = undefined; + absmins = undefined; + absmaxs = undefined; + wallmodel setmodel( model ); + wallmodel useweaponhidetags( weapon ); + mins = wallmodel getmins(); + maxs = wallmodel getmaxs(); + absmins = wallmodel getabsmins(); + absmaxs = wallmodel getabsmaxs(); + bounds = absmaxs - absmins; + unitrigger_stub.script_length = bounds[ 0 ] * 0.25; + unitrigger_stub.script_width = bounds[ 1 ]; + unitrigger_stub.script_height = bounds[ 2 ]; + unitrigger_stub.origin -= anglesToRight( unitrigger_stub.angles ) * ( unitrigger_stub.script_length * 0.4 ); + unitrigger_stub.target = spawned_wallbuy.target; + unitrigger_stub.targetname = "weapon_upgrade"; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + unitrigger_stub.first_time_triggered = !pristine; + if ( !is_melee_weapon( weapon ) ) + { + if ( pristine || weapon == "claymore_zm" ) + { + unitrigger_stub.hint_string = get_weapon_hint( weapon ); + } + else + { + unitrigger_stub.hint_string = get_weapon_hint_ammo(); + } + unitrigger_stub.cost = get_weapon_cost( weapon ); + unitrigger_stub.hint_parm1 = unitrigger_stub.cost; + } + unitrigger_stub.weapon_upgrade = weapon; + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + unitrigger_stub.require_look_at = 1; + unitrigger_stub.zombie_weapon_upgrade = weapon; + unitrigger_stub.clientfieldname = clientfieldname; + maps/mp/zombies/_zm_unitrigger::unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + if ( is_melee_weapon( weapon ) ) + { + if ( weapon == "tazer_knuckles_zm" && isDefined( level.taser_trig_adjustment ) ) + { + unitrigger_stub.origin += level.taser_trig_adjustment; + } + maps/mp/zombies/_zm_melee_weapon::add_stub( unitrigger_stub, weapon ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::melee_weapon_think ); + } + else if ( weapon == "claymore_zm" ) + { + unitrigger_stub.prompt_and_visibility_func = ::claymore_unitrigger_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::buy_claymores ); + } + else + { + unitrigger_stub.prompt_and_visibility_func = ::wall_weapon_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::weapon_spawn_think ); + } + spawned_wallbuy.trigger_stub = unitrigger_stub; + weaponidx = undefined; + if ( isDefined( level.buildable_wallbuy_weapons ) ) + { + for ( i = 0; i < level.buildable_wallbuy_weapons.size; i++ ) + { + if ( weapon == level.buildable_wallbuy_weapons[ i ] ) + { + weaponidx = i; + break; + } + } + } + if ( isDefined( weaponidx ) ) + { + level setclientfield( clientfieldname + "_idx", weaponidx + 1 ); + wallmodel delete(); + if ( !pristine ) + { + level setclientfield( clientfieldname, 1 ); + } + } + else + { + level setclientfield( clientfieldname, 1 ); + wallmodel show(); + } +} + +wall_weapon_update_prompt( player ) //checked partially changed to match cerberus output //partially changed at own discretion +{ + weapon = self.stub.zombie_weapon_upgrade; + if ( isDefined( level.monolingustic_prompt_format ) && !level.monolingustic_prompt_format ) + { + player_has_weapon = player has_weapon_or_upgrade( weapon ); + if ( !player_has_weapon && is_true( level.weapons_using_ammo_sharing ) ) + { + shared_ammo_weapon = player get_shared_ammo_weapon( self.zombie_weapon_upgrade ); + if ( isDefined( shared_ammo_weapon ) ) + { + weapon = shared_ammo_weapon; + player_has_weapon = 1; + } + } + if ( !player_has_weapon ) + { + cost = get_weapon_cost( weapon ); + self.stub.hint_string = get_weapon_hint( weapon ); + self sethintstring( self.stub.hint_string, cost ); + } + else if ( is_true( level.use_legacy_weapon_prompt_format ) ) + { + cost = get_weapon_cost( weapon ); + ammo_cost = get_ammo_cost( weapon ); + self.stub.hint_string = get_weapon_hint_ammo(); + self sethintstring( self.stub.hint_string, cost, ammo_cost ); + } + else if ( player has_upgrade( weapon ) ) + { + ammo_cost = get_upgraded_ammo_cost( weapon ); + } + else + { + ammo_cost = get_ammo_cost( weapon ); + } + self.stub.hint_string = &"ZOMBIE_WEAPONAMMOONLY"; + self sethintstring( self.stub.hint_string, ammo_cost ); + } + else if ( !player has_weapon_or_upgrade( weapon ) ) + { + string_override = 0; + if ( is_true( player.pers_upgrades_awarded[ "nube" ] ) ) + { + string_override = maps/mp/zombies/_zm_pers_upgrades_functions::pers_nube_ammo_hint_string( player, weapon ); + } + if ( !string_override ) + { + cost = get_weapon_cost( weapon ); + weapon_display = get_weapon_display_name( weapon ); + if ( !isDefined( weapon_display ) || weapon_display == "" || weapon_display == "none" ) + { + weapon_display = "missing weapon name " + weapon; + } + self.stub.hint_string = &"ZOMBIE_WEAPONCOSTONLY"; + self sethintstring( self.stub.hint_string, weapon_display, cost ); + } + } + else if ( player has_upgrade( weapon ) ) + { + ammo_cost = get_upgraded_ammo_cost( weapon ); + } + else + { + ammo_cost = get_ammo_cost( weapon ); + } + self.stub.hint_string = &"ZOMBIE_WEAPONAMMOONLY"; + self sethintstring( self.stub.hint_string, ammo_cost ); + self.stub.cursor_hint = "HINT_WEAPON"; + self.stub.cursor_hint_weapon = weapon; + self setcursorhint( self.stub.cursor_hint, self.stub.cursor_hint_weapon ); + return 1; +} + +reset_wallbuy_internal( set_hint_string ) //checked matches cerberus output +{ + if ( isDefined( self.first_time_triggered ) && self.first_time_triggered == 1 ) + { + self.first_time_triggered = 0; + if ( isDefined( self.clientfieldname ) ) + { + level setclientfield( self.clientfieldname, 0 ); + } + if ( set_hint_string ) + { + hint_string = get_weapon_hint( self.zombie_weapon_upgrade ); + cost = get_weapon_cost( self.zombie_weapon_upgrade ); + self sethintstring( hint_string, cost ); + } + } +} + +reset_wallbuys() //checked changed to match cerberus output +{ + weapon_spawns = []; + weapon_spawns = getentarray( "weapon_upgrade", "targetname" ); + melee_and_grenade_spawns = []; + melee_and_grenade_spawns = getentarray( "bowie_upgrade", "targetname" ); + melee_and_grenade_spawns = arraycombine( melee_and_grenade_spawns, getentarray( "sickle_upgrade", "targetname" ), 1, 0 ); + melee_and_grenade_spawns = arraycombine( melee_and_grenade_spawns, getentarray( "tazer_upgrade", "targetname" ), 1, 0 ); + if ( !is_true( level.headshots_only ) ) + { + melee_and_grenade_spawns = arraycombine( melee_and_grenade_spawns, getentarray( "claymore_purchase", "targetname" ), 1, 0 ); + } + for ( i = 0; i < weapon_spawns.size; i++ ) + { + weapon_spawns[ i ] reset_wallbuy_internal( 1 ); + } + for ( i = 0; i < melee_and_grenade_spawns.size; i++ ) + { + melee_and_grenade_spawns[ i ] reset_wallbuy_internal( 0 ); + } + if ( isDefined( level._unitriggers ) ) + { + candidates = []; + for ( i = 0; i < level._unitriggers.trigger_stubs.size; i++ ) + { + stub = level._unitriggers.trigger_stubs[ i ]; + tn = stub.targetname; + if ( tn == "weapon_upgrade" || tn == "bowie_upgrade" || tn == "sickle_upgrade" || tn == "tazer_upgrade" || tn == "claymore_purchase" ) + { + stub.first_time_triggered = 0; + if ( isDefined( stub.clientfieldname ) ) + { + level setclientfield( stub.clientfieldname, 0 ); + } + if ( tn == "weapon_upgrade" ) + { + stub.hint_string = get_weapon_hint( stub.zombie_weapon_upgrade ); + stub.cost = get_weapon_cost( stub.zombie_weapon_upgrade ); + stub.hint_parm1 = stub.cost; + } + } + } + } +} + +init_weapon_upgrade() //checked changed to match cerberus output +{ + init_spawnable_weapon_upgrade(); + weapon_spawns = []; + weapon_spawns = getentarray( "weapon_upgrade", "targetname" ); + for ( i = 0; i < weapon_spawns.size; i++ ) + { + if ( !is_true( level.monolingustic_prompt_format ) ) + { + hint_string = get_weapon_hint( weapon_spawns[ i ].zombie_weapon_upgrade ); + cost = get_weapon_cost( weapon_spawns[ i ].zombie_weapon_upgrade ); + weapon_spawns[ i ] sethintstring( hint_string, cost ); + weapon_spawns[ i ] setcursorhint( "HINT_NOICON" ); + } + else + { + cost = get_weapon_cost( weapon_spawns[ i ].zombie_weapon_upgrade ); + weapon_display = get_weapon_display_name( weapon_spawns[ i ].zombie_weapon_upgrade ); + if ( !isDefined( weapon_display ) || weapon_display == "" || weapon_display == "none" ) + { + weapon_display = "missing weapon name " + weapon_spawns[ i ].zombie_weapon_upgrade; + } + hint_string = &"ZOMBIE_WEAPONCOSTONLY"; + weapon_spawns[ i ] sethintstring( hint_string, weapon_display, cost ); + } + weapon_spawns[ i ] usetriggerrequirelookat(); + weapon_spawns[ i ] thread weapon_spawn_think(); + model = getent( weapon_spawns[ i ].target, "targetname" ); + if ( isDefined( model ) ) + { + model useweaponhidetags( weapon_spawns[ i ].zombie_weapon_upgrade ); + model hide(); + } + } +} + +init_weapon_toggle() //checked changed to match cerberus output +{ + if ( !isDefined( level.magic_box_weapon_toggle_init_callback ) ) + { + return; + } + level.zombie_weapon_toggles = []; + level.zombie_weapon_toggle_max_active_count = 0; + level.zombie_weapon_toggle_active_count = 0; + precachestring( &"ZOMBIE_WEAPON_TOGGLE_DISABLED" ); + precachestring( &"ZOMBIE_WEAPON_TOGGLE_ACTIVATE" ); + precachestring( &"ZOMBIE_WEAPON_TOGGLE_DEACTIVATE" ); + precachestring( &"ZOMBIE_WEAPON_TOGGLE_ACQUIRED" ); + level.zombie_weapon_toggle_disabled_hint = &"ZOMBIE_WEAPON_TOGGLE_DISABLED"; + level.zombie_weapon_toggle_activate_hint = &"ZOMBIE_WEAPON_TOGGLE_ACTIVATE"; + level.zombie_weapon_toggle_deactivate_hint = &"ZOMBIE_WEAPON_TOGGLE_DEACTIVATE"; + level.zombie_weapon_toggle_acquired_hint = &"ZOMBIE_WEAPON_TOGGLE_ACQUIRED"; + precachemodel( "zombie_zapper_cagelight" ); + precachemodel( "zombie_zapper_cagelight_green" ); + precachemodel( "zombie_zapper_cagelight_red" ); + precachemodel( "zombie_zapper_cagelight_on" ); + level.zombie_weapon_toggle_disabled_light = "zombie_zapper_cagelight"; + level.zombie_weapon_toggle_active_light = "zombie_zapper_cagelight_green"; + level.zombie_weapon_toggle_inactive_light = "zombie_zapper_cagelight_red"; + level.zombie_weapon_toggle_acquired_light = "zombie_zapper_cagelight_on"; + weapon_toggle_ents = []; + weapon_toggle_ents = getentarray( "magic_box_weapon_toggle", "targetname" ); + for ( i = 0; i < weapon_toggle_ents.size; i++ ) + { + struct = spawnstruct(); + struct.trigger = weapon_toggle_ents[ i ]; + struct.weapon_name = struct.trigger.script_string; + struct.upgrade_name = level.zombie_weapons[ struct.trigger.script_string ].upgrade_name; + struct.enabled = 0; + struct.active = 0; + struct.acquired = 0; + target_array = []; + target_array = getentarray( struct.trigger.target, "targetname" ); + for ( j = 0; j < target_array.size; j++ ) + { + switch( target_array[ j ].script_string ) + { + case "light": + struct.light = target_array[ j ]; + struct.light setmodel( level.zombie_weapon_toggle_disabled_light ); + break; + case "weapon": + struct.weapon_model = target_array[ j ]; + struct.weapon_model hide(); + break; + } + } + struct.trigger sethintstring( level.zombie_weapon_toggle_disabled_hint ); + struct.trigger setcursorhint( "HINT_NOICON" ); + struct.trigger usetriggerrequirelookat(); + struct thread weapon_toggle_think(); + level.zombie_weapon_toggles[ struct.weapon_name ] = struct; + } + level thread [[ level.magic_box_weapon_toggle_init_callback ]](); +} + +get_weapon_toggle( weapon_name ) //checked changed to match cerberus output +{ + if ( !isDefined( level.zombie_weapon_toggles ) ) + { + return undefined; + } + if ( isDefined( level.zombie_weapon_toggles[ weapon_name ] ) ) + { + return level.zombie_weapon_toggles[ weapon_name ]; + } + keys = getarraykeys( level.zombie_weapon_toggles ); + for ( i = 0; i < keys.size; i++ ) + { + if ( weapon_name == level.zombie_weapon_toggles[ keys[ i ] ].upgrade_name ) + { + return level.zombie_weapon_toggles[ keys[ i ] ]; + } + } + return undefined; +} + +is_weapon_toggle( weapon_name ) //checked matches cerberus output +{ + return isDefined( get_weapon_toggle( weapon_name ) ); +} + +disable_weapon_toggle( weapon_name ) //checked matches cerberus output +{ + toggle = get_weapon_toggle( weapon_name ); + if ( !isDefined( toggle ) ) + { + return; + } + if ( toggle.active ) + { + level.zombie_weapon_toggle_active_count--; + + } + toggle.enabled = 0; + toggle.active = 0; + toggle.light setmodel( level.zombie_weapon_toggle_disabled_light ); + toggle.weapon_model hide(); + toggle.trigger sethintstring( level.zombie_weapon_toggle_disabled_hint ); +} + +enable_weapon_toggle( weapon_name ) //checked matches cerberus output +{ + toggle = get_weapon_toggle( weapon_name ); + if ( !isDefined( toggle ) ) + { + return; + } + toggle.enabled = 1; + toggle.weapon_model show(); + toggle.weapon_model useweaponhidetags( weapon_name ); + deactivate_weapon_toggle( weapon_name ); +} + +activate_weapon_toggle( weapon_name, trig_for_vox ) //checked matches cerberus output +{ + if ( level.zombie_weapon_toggle_active_count >= level.zombie_weapon_toggle_max_active_count ) + { + if ( isDefined( trig_for_vox ) ) + { + trig_for_vox thread maps/mp/zombies/_zm_audio::weapon_toggle_vox( "max" ); + } + return; + } + toggle = get_weapon_toggle( weapon_name ); + if ( !isDefined( toggle ) ) + { + return; + } + if ( isDefined( trig_for_vox ) ) + { + trig_for_vox thread maps/mp/zombies/_zm_audio::weapon_toggle_vox( "activate", weapon_name ); + } + level.zombie_weapon_toggle_active_count++; + toggle.active = 1; + toggle.light setmodel( level.zombie_weapon_toggle_active_light ); + toggle.trigger sethintstring( level.zombie_weapon_toggle_deactivate_hint ); +} + +deactivate_weapon_toggle( weapon_name, trig_for_vox ) //checked matches cerberus output +{ + toggle = get_weapon_toggle( weapon_name ); + if ( !isDefined( toggle ) ) + { + return; + } + if ( isDefined( trig_for_vox ) ) + { + trig_for_vox thread maps/mp/zombies/_zm_audio::weapon_toggle_vox( "deactivate", weapon_name ); + } + if ( toggle.active ) + { + level.zombie_weapon_toggle_active_count--; + + } + toggle.active = 0; + toggle.light setmodel( level.zombie_weapon_toggle_inactive_light ); + toggle.trigger sethintstring( level.zombie_weapon_toggle_activate_hint ); +} + +acquire_weapon_toggle( weapon_name, player ) //checked matches cerberus output +{ + toggle = get_weapon_toggle( weapon_name ); + if ( !isDefined( toggle ) ) + { + return; + } + if ( !toggle.active || toggle.acquired ) + { + return; + } + toggle.acquired = 1; + toggle.light setmodel( level.zombie_weapon_toggle_acquired_light ); + toggle.trigger sethintstring( level.zombie_weapon_toggle_acquired_hint ); + toggle thread unacquire_weapon_toggle_on_death_or_disconnect_thread( player ); +} + +unacquire_weapon_toggle_on_death_or_disconnect_thread( player ) //checked matches cerberus output +{ + self notify( "end_unacquire_weapon_thread" ); + self endon( "end_unacquire_weapon_thread" ); + player waittill_any( "spawned_spectator", "disconnect" ); + unacquire_weapon_toggle( self.weapon_name ); +} + +unacquire_weapon_toggle( weapon_name ) //checked matches cerberus output +{ + toggle = get_weapon_toggle( weapon_name ); + if ( !isDefined( toggle ) ) + { + return; + } + if ( !toggle.active || !toggle.acquired ) + { + return; + } + toggle.acquired = 0; + toggle.light setmodel( level.zombie_weapon_toggle_active_light ); + toggle.trigger sethintstring( level.zombie_weapon_toggle_deactivate_hint ); + toggle notify( "end_unacquire_weapon_thread" ); +} + +weapon_toggle_think() //checked changed to match cerberus output +{ + for ( ;; ) + { + self.trigger waittill( "trigger", player ); + if ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0.5 ); + continue; + } + if ( !self.enabled || self.acquired ) + { + self.trigger thread maps/mp/zombies/_zm_audio::weapon_toggle_vox( "max" ); + continue; + } + if ( !self.active ) + { + activate_weapon_toggle( self.weapon_name, self.trigger ); + break; + } + deactivate_weapon_toggle( self.weapon_name, self.trigger ); + } +} + +get_weapon_hint( weapon_name ) //checked matches cerberus output +{ + return level.zombie_weapons[ weapon_name ].hint; +} + +get_weapon_cost( weapon_name ) //checked matches cerberus output +{ + return level.zombie_weapons[ weapon_name ].cost; +} + +get_ammo_cost( weapon_name ) //checked matches cerberus output +{ + return level.zombie_weapons[ weapon_name ].ammo_cost; +} + +get_upgraded_ammo_cost( weapon_name ) //checked matches cerberus output +{ + if ( isDefined( level.zombie_weapons[ weapon_name ].upgraded_ammo_cost ) ) + { + return level.zombie_weapons[ weapon_name ].upgraded_ammo_cost; + } + return 4500; +} + +get_weapon_display_name( weapon_name ) //checked changed to match cerberus output +{ + weapon_display = getweapondisplayname( weapon_name ); + if ( !isDefined( weapon_display ) || weapon_display == "" || weapon_display == "none" ) + { + weapon_display = &"MPUI_NONE"; + } + return weapon_display; +} + +get_is_in_box( weapon_name ) //checked matches cerberus output +{ + return level.zombie_weapons[ weapon_name ].is_in_box; +} + +weapon_supports_default_attachment( weaponname ) //checked matches cerberus output +{ + weaponname = get_base_weapon_name( weaponname ); + if ( isDefined( weaponname ) ) + { + attachment = level.zombie_weapons[ weaponname ].default_attachment; + } + return isDefined( attachment ); +} + +default_attachment( weaponname ) //checked matches cerberus output +{ + weaponname = get_base_weapon_name( weaponname ); + if ( isDefined( weaponname ) ) + { + attachment = level.zombie_weapons[ weaponname ].default_attachment; + } + if ( isDefined( attachment ) ) + { + return attachment; + } + else + { + return "none"; + } +} + +weapon_supports_attachments( weaponname ) //checked changed at own discretion +{ + weaponname = get_base_weapon_name( weaponname ); + if ( isDefined( weaponname ) ) + { + attachments = level.zombie_weapons[ weaponname ].addon_attachments; + } + if ( isDefined( attachments ) && attachments.size > 0 ) //was 1 + { + return 1; + } + return 0; +} + +random_attachment( weaponname, exclude ) //checked changed to match cerberus output +{ + lo = 0; + if ( isDefined( level.zombie_weapons[ weaponname ].addon_attachments ) && level.zombie_weapons[ weaponname ].addon_attachments.size > 0 ) + { + attachments = level.zombie_weapons[ weaponname ].addon_attachments; + } + else + { + attachments = getweaponsupportedattachments( weaponname ); + lo = 1; + } + minatt = lo; + if ( isDefined( exclude ) && exclude != "none" ) + { + minatt = lo + 1; + } + if ( attachments.size > minatt ) + { + while ( 1 ) + { + idx = randomint( attachments.size - lo ) + lo; + if ( !isDefined( exclude ) || attachments[ idx ] != exclude ) + { + return attachments[ idx ]; + } + } + } + return "none"; +} + +get_base_name( weaponname ) //checked matches cerberus output +{ + split = strtok( weaponname, "+" ); + if ( split.size > 1 ) + { + return split[ 0 ]; + } + return weaponname; +} + +get_attachment_name( weaponname, att_id ) //checked changed to match cerberus output +{ + split = strtok( weaponname, "+" ); + if ( isDefined( att_id ) ) + { + attachment = att_id + 1; + if ( split.size > attachment ) + { + return split[ attachment ]; + } + } + else if ( split.size > 1 ) + { + att = split[ 1 ]; + for ( idx = 2; split.size > idx; idx++ ) + { + att = ( att + "+" ) + split[ idx ]; + } + return att; + } + return undefined; +} + +get_attachment_index( weapon ) //checked changed to match cerberus output +{ + att = get_attachment_name( weapon ); + if ( att == "none" ) + { + return -1; + } + base = get_base_name( weapon ); + if ( att == level.zombie_weapons[ base ].default_attachment ) + { + return 0; + } + if ( isDefined( level.zombie_weapons[ base ].addon_attachments ) ) + { + for ( i = 0; i < level.zombie_weapons[base].addon_attachments.size; i++ ) + { + if ( level.zombie_weapons[ base ].addon_attachments[ i ] == att ) + { + return i + 1; + } + } + } + return -1; +} + +weapon_supports_this_attachment( weapon, att ) //checked changed to match cerberus output +{ + base = get_base_name( weapon ); + if ( att == level.zombie_weapons[ base ].default_attachment ) + { + return 1; + } + if ( isDefined( level.zombie_weapons[ base ].addon_attachments ) ) + { + for(i = 0; i < level.zombie_weapons[base].addon_attachments.size; i++) + { + if ( level.zombie_weapons[ base ].addon_attachments[ i ] == att ) + { + return 1; + } + } + } + return 0; +} + +has_attachment( weaponname, att ) //checked matches cerberus output +{ + split = strtok( weaponname, "+" ); + idx = 1; + while ( split.size > idx ) + { + if ( att == split[ idx ] ) + { + return 1; + } + } + return 0; +} + +get_base_weapon_name( upgradedweaponname, base_if_not_upgraded ) //checked matches cerberus output +{ + if ( !isDefined( upgradedweaponname ) || upgradedweaponname == "" ) + { + return undefined; + } + upgradedweaponname = tolower( upgradedweaponname ); + upgradedweaponname = get_base_name( upgradedweaponname ); + if ( isDefined( level.zombie_weapons_upgraded[ upgradedweaponname ] ) ) + { + return level.zombie_weapons_upgraded[ upgradedweaponname ]; + } + if ( isDefined( base_if_not_upgraded ) && base_if_not_upgraded ) + { + return upgradedweaponname; + } + return undefined; +} + +get_upgrade_weapon( weaponname, add_attachment ) //checked changed to match cerberus output +{ + rootweaponname = tolower( weaponname ); + rootweaponname = get_base_name( rootweaponname ); + baseweaponname = get_base_weapon_name( rootweaponname, 1 ); + newweapon = rootweaponname; + if ( !is_weapon_upgraded( rootweaponname ) ) + { + newweapon = level.zombie_weapons[ rootweaponname ].upgrade_name; + } + if ( is_true( add_attachment ) && is_true( level.zombiemode_reusing_pack_a_punch ) ) + { + oldatt = get_attachment_name( weaponname ); + att = random_attachment( baseweaponname, oldatt ); + newweapon = newweapon + "+" + att; + } + else if ( isDefined( level.zombie_weapons[ rootweaponname ] ) && isDefined( level.zombie_weapons[ rootweaponname ].default_attachment ) ) + { + att = level.zombie_weapons[ rootweaponname ].default_attachment; + newweapon = newweapon + "+" + att; + } + return newweapon; +} + +can_upgrade_weapon( weaponname ) //checked changed to match cerberus output +{ + if ( !isDefined( weaponname ) || weaponname == "" || weaponname == "zombie_fists_zm" ) + { + return 0; + } + weaponname = tolower( weaponname ); + weaponname = get_base_name( weaponname ); + if ( !is_weapon_upgraded( weaponname ) && isDefined( level.zombie_weapons[ weaponname ].upgrade_name ) ) + { + return 1; + } + if ( is_true( level.zombiemode_reusing_pack_a_punch ) && weapon_supports_attachments( weaponname ) ) + { + return 1; + } + return 0; +} + +will_upgrade_weapon_as_attachment( weaponname ) //checked changed to match cerberus output +{ + if ( !isDefined( weaponname ) || weaponname == "" || weaponname == "zombie_fists_zm" ) + { + return 0; + } + weaponname = tolower( weaponname ); + weaponname = get_base_name( weaponname ); + if ( !is_weapon_upgraded( weaponname ) ) + { + return 0; + } + if ( is_true( level.zombiemode_reusing_pack_a_punch ) && weapon_supports_attachments( weaponname ) ) + { + return 1; + } + return 0; +} + +is_weapon_upgraded( weaponname ) //checked changed to match cerberus output +{ + if ( !isDefined( weaponname ) || weaponname == "" || weaponname == "zombie_fists_zm" ) + { + return 0; + } + weaponname = tolower( weaponname ); + weaponname = get_base_name( weaponname ); + if ( isDefined( level.zombie_weapons_upgraded[ weaponname ] ) ) + { + return 1; + } + return 0; +} + +get_weapon_with_attachments( weaponname ) //checked changed to match cerberus output +{ + if ( self hasweapon( weaponname ) ) + { + return weaponname; + } + if ( is_true( level.zombiemode_reusing_pack_a_punch ) ) + { + weaponname = tolower( weaponname ); + weaponname = get_base_name( weaponname ); + weapons = self getweaponslist( 1 ); + foreach ( weapon in weapons ) + { + weapon = tolower( weapon ); + weapon_base = get_base_name( weapon ); + if ( weaponname == weapon_base ) + { + return weapon; + } + } + } + return undefined; +} + +has_weapon_or_attachments( weaponname ) //checked changed to match cerberus output +{ + if ( self hasweapon( weaponname ) ) + { + return 1; + } + if ( is_true( level.zombiemode_reusing_pack_a_punch ) ) + { + weaponname = tolower( weaponname ); + weaponname = get_base_name( weaponname ); + weapons = self getweaponslist( 1 ); + foreach ( weapon in weapons ) + { + weapon = tolower( weapon ); + weapon = get_base_name( weapon ); + if ( weaponname == weapon ) + { + return 1; + } + } + } + return 0; +} + +has_upgrade( weaponname ) //checked matches cerberus output +{ + weaponname = get_base_name( weaponname ); + has_upgrade = 0; + if ( isDefined( level.zombie_weapons[ weaponname ] ) && isDefined( level.zombie_weapons[ weaponname ].upgrade_name ) ) + { + has_upgrade = self has_weapon_or_attachments( level.zombie_weapons[ weaponname ].upgrade_name ); + } + if ( !has_upgrade && weaponname == "knife_ballistic_zm" ) + { + has_weapon = self maps/mp/zombies/_zm_melee_weapon::has_upgraded_ballistic_knife(); + } + return has_upgrade; +} + +has_weapon_or_upgrade( weaponname ) //checked changed at own discretion +{ + weaponname = get_base_name( weaponname ); + upgradedweaponname = weaponname; + if ( isDefined( level.zombie_weapons[ weaponname ] ) && isDefined( level.zombie_weapons[ weaponname ].upgrade_name ) ) + { + upgradedweaponname = level.zombie_weapons[ weaponname ].upgrade_name; + } + has_weapon = 0; + if ( isDefined( level.zombie_weapons[ weaponname ] ) ) + { + if ( self has_weapon_or_attachments( weaponname ) || self has_upgrade( weaponname ) ) + { + has_weapon = 1; + } + } + if ( !has_weapon && weaponname == "knife_ballistic_zm" ) + { + has_weapon = self maps/mp/zombies/_zm_melee_weapon::has_any_ballistic_knife(); + } + if ( !has_weapon && is_equipment( weaponname ) ) + { + has_weapon = self is_equipment_active( weaponname ); + } + return has_weapon; +} + +add_shared_ammo_weapon( str_weapon, str_base_weapon ) //checked matches cerberus output +{ + level.zombie_weapons[ str_weapon ].shared_ammo_weapon = str_base_weapon; +} + +get_shared_ammo_weapon( base_weapon ) //checked changed to match cerberus output +{ + base_weapon = get_base_name( base_weapon ); + weapons = self getweaponslist( 1 ); + foreach ( weapon in weapons ) + { + weapon = tolower( weapon ); + weapon = get_base_name( weapon ); + if ( !isdefined( level.zombie_weapons[ weapon ] ) && isdefined( level.zombie_weapons_upgraded[ weapon ] ) ) + { + weapon = level.zombie_weapons_upgraded[ weapon ]; + } + if ( isdefined( level.zombie_weapons[ weapon ] ) && isdefined( level.zombie_weapons[ weapon ].shared_ammo_weapon ) && level.zombie_weapons[ weapon ].shared_ammo_weapon == base_weapon ) + { + return weapon; + } + } + return undefined; +} + +get_player_weapon_with_same_base( weaponname ) //checked changed tp match cerberus output +{ + weaponname = tolower( weaponname ); + weaponname = get_base_name( weaponname ); + retweapon = get_weapon_with_attachments( weaponname ); + if ( !isDefined( retweapon ) ) + { + if ( isDefined( level.zombie_weapons[ weaponname ] ) ) + { + retweapon = get_weapon_with_attachments( level.zombie_weapons[ weaponname ].upgrade_name ); + } + else if ( isDefined( level.zombie_weapons_upgraded[ weaponname ] ) ) + { + return get_weapon_with_attachments( level.zombie_weapons_upgraded[ weaponname ] ); + } + } + return retweapon; +} + +get_weapon_hint_ammo() //checked matches cerberus output +{ + if ( !is_true( level.has_pack_a_punch ) ) + { + return &"ZOMBIE_WEAPONCOSTAMMO"; + } + else + { + return &"ZOMBIE_WEAPONCOSTAMMO_UPGRADE"; + } +} + +weapon_set_first_time_hint( cost, ammo_cost ) //checked matches cerberus output +{ + self sethintstring( get_weapon_hint_ammo(), cost, ammo_cost ); +} + +weapon_spawn_think() //checked changed to match cerberus output +{ + cost = get_weapon_cost( self.zombie_weapon_upgrade ); + ammo_cost = get_ammo_cost( self.zombie_weapon_upgrade ); + is_grenade = weapontype( self.zombie_weapon_upgrade ) == "grenade"; + shared_ammo_weapon = undefined; + second_endon = undefined; + if ( isDefined( self.stub ) ) + { + second_endon = "kill_trigger"; + self.first_time_triggered = self.stub.first_time_triggered; + } + if ( isDefined( self.stub ) && is_true( self.stub.trigger_per_player ) ) + { + self thread decide_hide_show_hint( "stop_hint_logic", second_endon, self.parent_player ); + } + else + { + self thread decide_hide_show_hint( "stop_hint_logic", second_endon ); + } + if ( is_grenade ) + { + self.first_time_triggered = 0; + hint = get_weapon_hint( self.zombie_weapon_upgrade ); + self sethintstring( hint, cost ); + } + else if ( !isDefined( self.first_time_triggered ) ) + { + self.first_time_triggered = 0; + if ( isDefined( self.stub ) ) + { + self.stub.first_time_triggered = 0; + } + } + else if ( self.first_time_triggered ) + { + if ( is_true( level.use_legacy_weapon_prompt_format ) ) + { + self weapon_set_first_time_hint( cost, get_ammo_cost( self.zombie_weapon_upgrade ) ); + } + } + for ( ;; ) + { + self waittill( "trigger", player ); + if ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0.5 ); + continue; + } + if ( !player can_buy_weapon() ) + { + wait 0.1; + continue; + } + if ( isDefined( self.stub ) && is_true( self.stub.require_look_from ) ) + { + toplayer = player get_eye() - self.origin; + forward = -1 * anglesToRight( self.angles ); + dot = vectordot( toplayer, forward ); + if ( dot < 0 ) + { + continue; + } + } + if ( player has_powerup_weapon() ) + { + wait 0.1; + continue; + } + player_has_weapon = player has_weapon_or_upgrade( self.zombie_weapon_upgrade ); + if ( !player_has_weapon && is_true( level.weapons_using_ammo_sharing ) ) + { + shared_ammo_weapon = player get_shared_ammo_weapon( self.zombie_weapon_upgrade ); + if ( isDefined( shared_ammo_weapon ) ) + { + player_has_weapon = 1; + } + } + if ( is_true( level.pers_upgrade_nube ) ) + { + player_has_weapon = maps/mp/zombies/_zm_pers_upgrades_functions::pers_nube_should_we_give_raygun( player_has_weapon, player, self.zombie_weapon_upgrade ); + } + cost = get_weapon_cost( self.zombie_weapon_upgrade ); + if ( player maps/mp/zombies/_zm_pers_upgrades_functions::is_pers_double_points_active() ) + { + cost = int( cost / 2 ); + } + if ( !player_has_weapon ) + { + if ( player.score >= cost ) + { + if ( self.first_time_triggered == 0 ) + { + self show_all_weapon_buys( player, cost, ammo_cost, is_grenade ); + } + player maps/mp/zombies/_zm_score::minus_to_player_score( cost, 1 ); + bbprint( "zombie_uses", "playername %s playerscore %d round %d cost %d name %s x %f y %f z %f type %s", player.name, player.score, level.round_number, cost, self.zombie_weapon_upgrade, self.origin, "weapon" ); + level notify( "weapon_bought", player, self.zombie_weapon_upgrade ); + if ( self.zombie_weapon_upgrade == "riotshield_zm" ) + { + player maps/mp/zombies/_zm_equipment::equipment_give( "riotshield_zm" ); + if ( isDefined( player.player_shield_reset_health ) ) + { + player [[ player.player_shield_reset_health ]](); + } + } + else if ( self.zombie_weapon_upgrade == "jetgun_zm" ) + { + player maps/mp/zombies/_zm_equipment::equipment_give( "jetgun_zm" ); + } + else if ( is_lethal_grenade( self.zombie_weapon_upgrade ) ) + { + player takeweapon( player get_player_lethal_grenade() ); + player set_player_lethal_grenade( self.zombie_weapon_upgrade ); + } + str_weapon = self.zombie_weapon_upgrade; + if ( is_true( level.pers_upgrade_nube ) ) + { + str_weapon = maps/mp/zombies/_zm_pers_upgrades_functions::pers_nube_weapon_upgrade_check( player, str_weapon ); + } + player weapon_give( str_weapon ); + player maps/mp/zombies/_zm_stats::increment_client_stat( "wallbuy_weapons_purchased" ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "wallbuy_weapons_purchased" ); + } + else + { + play_sound_on_ent( "no_purchase" ); + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "no_money_weapon" ); + } + } + else + { + str_weapon = self.zombie_weapon_upgrade; + if ( isDefined( shared_ammo_weapon ) ) + { + str_weapon = shared_ammo_weapon; + } + if ( is_true( level.pers_upgrade_nube ) ) + { + str_weapon = maps/mp/zombies/_zm_pers_upgrades_functions::pers_nube_weapon_ammo_check( player, str_weapon ); + } + if ( is_true( self.hacked ) ) + { + if ( !player has_upgrade( str_weapon ) ) + { + ammo_cost = 4500; + } + else + { + ammo_cost = get_ammo_cost( str_weapon ); + } + } + else if ( player has_upgrade( str_weapon ) ) + { + ammo_cost = 4500; + } + else + { + ammo_cost = get_ammo_cost( str_weapon ); + } + if ( is_true( player.pers_upgrades_awarded[ "nube" ] ) ) + { + ammo_cost = maps/mp/zombies/_zm_pers_upgrades_functions::pers_nube_override_ammo_cost( player, self.zombie_weapon_upgrade, ammo_cost ); + } + if ( player maps/mp/zombies/_zm_pers_upgrades_functions::is_pers_double_points_active() ) + { + ammo_cost = int( ammo_cost / 2 ); + } + if ( str_weapon == "riotshield_zm" ) + { + play_sound_on_ent( "no_purchase" ); + } + else if ( player.score >= ammo_cost ) + { + if ( self.first_time_triggered == 0 ) + { + self show_all_weapon_buys( player, cost, ammo_cost, is_grenade ); + } + if ( player has_upgrade( str_weapon ) ) + { + player maps/mp/zombies/_zm_stats::increment_client_stat( "upgraded_ammo_purchased" ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "upgraded_ammo_purchased" ); + } + else + { + player maps/mp/zombies/_zm_stats::increment_client_stat( "ammo_purchased" ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "ammo_purchased" ); + } + if ( str_weapon == "riotshield_zm" ) + { + if ( isDefined( player.player_shield_reset_health ) ) + { + ammo_given = player [[ player.player_shield_reset_health ]](); + } + else + { + ammo_given = 0; + } + } + else if ( player has_upgrade( str_weapon ) ) + { + ammo_given = player ammo_give( level.zombie_weapons[ str_weapon ].upgrade_name ); + } + else + { + ammo_given = player ammo_give( str_weapon ); + } + if ( ammo_given ) + { + player maps/mp/zombies/_zm_score::minus_to_player_score( ammo_cost, 1 ); + bbprint( "zombie_uses", "playername %s playerscore %d round %d cost %d name %s x %f y %f z %f type %s", player.name, player.score, level.round_number, ammo_cost, str_weapon, self.origin, "ammo" ); + } + } + else + { + play_sound_on_ent( "no_purchase" ); + if ( isDefined( level.custom_generic_deny_vo_func ) ) + { + player [[ level.custom_generic_deny_vo_func ]](); + } + else + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "no_money_weapon" ); + } + } + } + if ( isDefined( self.stub ) && isDefined( self.stub.prompt_and_visibility_func ) ) + { + self [[ self.stub.prompt_and_visibility_func ]]( player ); + } + } +} + +show_all_weapon_buys( player, cost, ammo_cost, is_grenade ) //checked changed to match cerberus output +{ + model = getent( self.target, "targetname" ); + if ( isDefined( model ) ) + { + model thread weapon_show( player ); + } + else if ( isDefined( self.clientfieldname ) ) + { + level setclientfield( self.clientfieldname, 1 ); + } + self.first_time_triggered = 1; + if ( isDefined( self.stub ) ) + { + self.stub.first_time_triggered = 1; + } + if ( !is_grenade ) + { + self weapon_set_first_time_hint( cost, ammo_cost ); + } + if ( !is_true( level.dont_link_common_wallbuys ) && isDefined( level._spawned_wallbuys ) ) + { + i = 0; + while ( i < level._spawned_wallbuys.size ) + { + wallbuy = level._spawned_wallbuys[ i ]; + if ( isDefined( self.stub ) && isDefined( wallbuy.trigger_stub ) && self.stub.clientfieldname == wallbuy.trigger_stub.clientfieldname ) + { + i++; + continue; + } + if ( self.zombie_weapon_upgrade == wallbuy.zombie_weapon_upgrade ) + { + if ( isDefined( wallbuy.trigger_stub ) && isDefined( wallbuy.trigger_stub.clientfieldname ) ) + { + level setclientfield( wallbuy.trigger_stub.clientfieldname, 1 ); + } + else if ( isDefined( wallbuy.target ) ) + { + model = getent( wallbuy.target, "targetname" ); + if ( isDefined( model ) ) + { + model thread weapon_show( player ); + } + } + if ( isDefined( wallbuy.trigger_stub ) ) + { + wallbuy.trigger_stub.first_time_triggered = 1; + if ( isDefined( wallbuy.trigger_stub.trigger ) ) + { + wallbuy.trigger_stub.trigger.first_time_triggered = 1; + if ( !is_grenade ) + { + wallbuy.trigger_stub.trigger weapon_set_first_time_hint( cost, ammo_cost ); + } + } + i++; + continue; + } + if ( !is_grenade ) + { + wallbuy weapon_set_first_time_hint( cost, ammo_cost ); + } + } + i++; + } + } +} + +weapon_show( player ) //checked matches cerberus output +{ + player_angles = vectorToAngles( player.origin - self.origin ); + player_yaw = player_angles[ 1 ]; + weapon_yaw = self.angles[ 1 ]; + if ( isDefined( self.script_int ) ) + { + weapon_yaw -= self.script_int; + } + yaw_diff = absAngleClamp180( player_yaw - weapon_yaw ); + if ( yaw_diff > 0 ) + { + yaw = weapon_yaw - 90; + } + else + { + yaw = weapon_yaw + 90; + } + self.og_origin = self.origin; + self.origin += anglesToForward( ( 0, yaw, 0 ) ) * 8; + wait 0.05; + self show(); + play_sound_at_pos( "weapon_show", self.origin, self ); + time = 1; + if ( !isDefined( self._linked_ent ) ) + { + self moveto( self.og_origin, time ); + } +} + +get_pack_a_punch_weapon_options( weapon ) //checked changed to match cerberus output +{ + if ( !isDefined( self.pack_a_punch_weapon_options ) ) + { + self.pack_a_punch_weapon_options = []; + } + if ( !is_weapon_upgraded( weapon ) ) + { + return self calcweaponoptions( 0, 0, 0, 0, 0 ); + } + if ( isDefined( self.pack_a_punch_weapon_options[ weapon ] ) ) + { + return self.pack_a_punch_weapon_options[ weapon ]; + } + smiley_face_reticle_index = 1; + base = get_base_name( weapon ); + camo_index = 39; + if ( level.script == "zm_prison" ) + { + camo_index = 40; + } + else if ( level.script == "zm_tomb" ) + { + camo_index = 45; + } + lens_index = randomintrange( 0, 6 ); + reticle_index = randomintrange( 0, 16 ); + reticle_color_index = randomintrange( 0, 6 ); + plain_reticle_index = 16; + r = randomint( 10 ); + use_plain = r < 3; + if ( base == "saritch_upgraded_zm" ) + { + reticle_index = smiley_face_reticle_index; + } + else if ( use_plain ) + { + reticle_index = plain_reticle_index; + } + scary_eyes_reticle_index = 8; + purple_reticle_color_index = 3; + if ( reticle_index == scary_eyes_reticle_index ) + { + reticle_color_index = purple_reticle_color_index; + } + letter_a_reticle_index = 2; + pink_reticle_color_index = 6; + if ( reticle_index == letter_a_reticle_index ) + { + reticle_color_index = pink_reticle_color_index; + } + letter_e_reticle_index = 7; + green_reticle_color_index = 1; + if ( reticle_index == letter_e_reticle_index ) + { + reticle_color_index = green_reticle_color_index; + } + self.pack_a_punch_weapon_options[ weapon ] = self calcweaponoptions( camo_index, lens_index, reticle_index, reticle_color_index ); + return self.pack_a_punch_weapon_options[ weapon ]; +} + +weapon_give( weapon, is_upgrade, magic_box, nosound ) //checked changed to match cerberus output +{ + primaryweapons = self getweaponslistprimaries(); + current_weapon = self getcurrentweapon(); + current_weapon = self maps/mp/zombies/_zm_weapons::switch_from_alt_weapon( current_weapon ); + if ( !isDefined( is_upgrade ) ) + { + is_upgrade = 0; + } + weapon_limit = get_player_weapon_limit( self ); + if ( is_equipment( weapon ) ) + { + self maps/mp/zombies/_zm_equipment::equipment_give( weapon ); + } + if ( weapon == "riotshield_zm" ) + { + if ( isDefined( self.player_shield_reset_health ) ) + { + self [[ self.player_shield_reset_health ]](); + } + } + if ( self hasweapon( weapon ) ) + { + if ( issubstr( weapon, "knife_ballistic_" ) ) + { + self notify( "zmb_lost_knife" ); + } + self givestartammo( weapon ); + if ( !is_offhand_weapon( weapon ) ) + { + self switchtoweapon( weapon ); + } + return; + } + if ( is_melee_weapon( weapon ) ) + { + current_weapon = maps/mp/zombies/_zm_melee_weapon::change_melee_weapon( weapon, current_weapon ); + } + else if ( is_lethal_grenade( weapon ) ) + { + old_lethal = self get_player_lethal_grenade(); + if ( isDefined( old_lethal ) && old_lethal != "" ) + { + self takeweapon( old_lethal ); + unacquire_weapon_toggle( old_lethal ); + } + self set_player_lethal_grenade( weapon ); + } + else if ( is_tactical_grenade( weapon ) ) + { + old_tactical = self get_player_tactical_grenade(); + if ( isDefined( old_tactical ) && old_tactical != "" ) + { + self takeweapon( old_tactical ); + unacquire_weapon_toggle( old_tactical ); + } + self set_player_tactical_grenade( weapon ); + } + else if ( is_placeable_mine( weapon ) ) + { + old_mine = self get_player_placeable_mine(); + if ( isDefined( old_mine ) ) + { + self takeweapon( old_mine ); + unacquire_weapon_toggle( old_mine ); + } + self set_player_placeable_mine( weapon ); + } + if ( !is_offhand_weapon( weapon ) ) + { + self maps/mp/zombies/_zm_weapons::take_fallback_weapon(); + } + if ( primaryweapons.size >= weapon_limit ) + { + if ( is_placeable_mine( current_weapon ) || is_equipment( current_weapon ) ) + { + current_weapon = undefined; + } + if ( isDefined( current_weapon ) ) + { + if ( !is_offhand_weapon( weapon ) ) + { + if ( current_weapon == "tesla_gun_zm" ) + { + level.player_drops_tesla_gun = 1; + } + if ( issubstr( current_weapon, "knife_ballistic_" ) ) + { + self notify( "zmb_lost_knife" ); + } + self takeweapon( current_weapon ); + unacquire_weapon_toggle( current_weapon ); + } + } + } + if ( isDefined( level.zombiemode_offhand_weapon_give_override ) ) + { + if ( self [[ level.zombiemode_offhand_weapon_give_override ]]( weapon ) ) + { + return; + } + } + if ( weapon == "cymbal_monkey_zm" ) + { + self maps/mp/zombies/_zm_weap_cymbal_monkey::player_give_cymbal_monkey(); + self play_weapon_vo( weapon, magic_box ); + return; + } + else if ( issubstr( weapon, "knife_ballistic_" ) ) + { + weapon = self maps/mp/zombies/_zm_melee_weapon::give_ballistic_knife( weapon, issubstr( weapon, "upgraded" ) ); + } + else if ( weapon == "claymore_zm" ) + { + self thread maps/mp/zombies/_zm_weap_claymore::claymore_setup(); + self play_weapon_vo( weapon, magic_box ); + return; + } + if ( isDefined( level.zombie_weapons_callbacks ) && isDefined( level.zombie_weapons_callbacks[ weapon ] ) ) + { + self thread [[ level.zombie_weapons_callbacks[ weapon ] ]](); + play_weapon_vo( weapon, magic_box ); + return; + } + if ( !is_true( nosound ) ) + { + self play_sound_on_ent( "purchase" ); + } + if ( weapon == "ray_gun_zm" ) + { + playsoundatposition( "mus_raygun_stinger", ( 0, 0, 0 ) ); + } + if ( !is_weapon_upgraded( weapon ) ) + { + self giveweapon( weapon ); + } + else + { + self giveweapon( weapon, 0, self get_pack_a_punch_weapon_options( weapon ) ); + } + acquire_weapon_toggle( weapon, self ); + self givestartammo( weapon ); + if ( !is_offhand_weapon( weapon ) ) + { + if ( !is_melee_weapon( weapon ) ) + { + self switchtoweapon( weapon ); + } + else + { + self switchtoweapon( current_weapon ); + } + } + self play_weapon_vo( weapon, magic_box ); +} + +play_weapon_vo( weapon, magic_box ) //checked matches cerberus output +{ + if ( isDefined( level._audio_custom_weapon_check ) ) + { + type = self [[ level._audio_custom_weapon_check ]]( weapon, magic_box ); + } + else + { + type = self weapon_type_check( weapon ); + } + if ( type == "crappy" ) + { + return; + } + if ( type != "favorite" && type != "upgrade" ) + { + type = weapon; + } + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", type ); +} + +weapon_type_check( weapon ) //checked matches cerberus output +{ + if ( !isDefined( self.entity_num ) ) + { + return "crappy"; + } + weapon = get_base_name( weapon ); + if ( self is_favorite_weapon( weapon ) ) + { + return "favorite"; + } + if ( issubstr( weapon, "upgraded" ) ) + { + return "upgrade"; + } + else + { + return level.zombie_weapons[ weapon ].vox; + } +} + +get_player_index( player ) //checked matches cerberus output +{ + return player.characterindex; +} + +ammo_give( weapon ) //checked changed to match cerberus output +{ + give_ammo = 0; + if ( !is_offhand_weapon( weapon ) ) + { + weapon = get_weapon_with_attachments( weapon ); + if ( isDefined( weapon ) ) + { + stockmax = 0; + stockmax = weaponstartammo( weapon ); + clipcount = self getweaponammoclip( weapon ); + currstock = self getammocount( weapon ); + if ( ( currstock - clipcount ) >= stockmax ) + { + give_ammo = 0; + } + else + { + give_ammo = 1; + } + } + } + else if ( self has_weapon_or_upgrade( weapon ) ) + { + if ( self getammocount( weapon ) < weaponmaxammo( weapon ) ) + { + give_ammo = 1; + } + } + if ( give_ammo ) + { + self play_sound_on_ent( "purchase" ); + self givemaxammo( weapon ); + alt_weap = weaponaltweaponname( weapon ); + if ( alt_weap != "none" ) + { + self givemaxammo( alt_weap ); + } + return 1; + } + if ( !give_ammo ) + { + return 0; + } +} + +get_player_weapondata( player, weapon ) //checked matches cerberus output +{ + weapondata = []; + if ( !isDefined( weapon ) ) + { + weapondata[ "name" ] = player getcurrentweapon(); + } + else + { + weapondata[ "name" ] = weapon; + } + weapondata[ "dw_name" ] = weapondualwieldweaponname( weapondata[ "name" ] ); + weapondata[ "alt_name" ] = weaponaltweaponname( weapondata[ "name" ] ); + if ( weapondata[ "name" ] != "none" ) + { + weapondata[ "clip" ] = player getweaponammoclip( weapondata[ "name" ] ); + weapondata[ "stock" ] = player getweaponammostock( weapondata[ "name" ] ); + weapondata[ "fuel" ] = player getweaponammofuel( weapondata[ "name" ] ); + weapondata[ "heat" ] = player isweaponoverheating( 1, weapondata[ "name" ] ); + weapondata[ "overheat" ] = player isweaponoverheating( 0, weapondata[ "name" ] ); + } + else + { + weapondata[ "clip" ] = 0; + weapondata[ "stock" ] = 0; + weapondata[ "fuel" ] = 0; + weapondata[ "heat" ] = 0; + weapondata[ "overheat" ] = 0; + } + if ( weapondata[ "dw_name" ] != "none" ) + { + weapondata[ "lh_clip" ] = player getweaponammoclip( weapondata[ "dw_name" ] ); + } + else + { + weapondata[ "lh_clip" ] = 0; + } + if ( weapondata[ "alt_name" ] != "none" ) + { + weapondata[ "alt_clip" ] = player getweaponammoclip( weapondata[ "alt_name" ] ); + weapondata[ "alt_stock" ] = player getweaponammostock( weapondata[ "alt_name" ] ); + } + else + { + weapondata[ "alt_clip" ] = 0; + weapondata[ "alt_stock" ] = 0; + } + return weapondata; +} + +weapon_is_better( left, right ) //checked changed to match cerberus output +{ + if ( left != right ) + { + left_upgraded = !isDefined( level.zombie_weapons[ left ] ); + right_upgraded = !isDefined( level.zombie_weapons[ right ] ); + if ( left_upgraded && right_upgraded ) + { + leftatt = get_attachment_index( left ); + rightatt = get_attachment_index( right ); + return leftatt > rightatt; + } + else if ( left_upgraded ) + { + return 1; + } + } + return 0; +} + +merge_weapons( oldweapondata, newweapondata ) //checked matches cerberus output +{ + weapondata = []; + weapondata[ "name" ] = "none"; + if ( weapon_is_better( oldweapondata[ "name" ], newweapondata[ "name" ] ) ) + { + weapondata[ "name" ] = oldweapondata[ "name" ]; + } + else + { + weapondata[ "name" ] = newweapondata[ "name" ]; + } + name = weapondata[ "name" ]; + dw_name = weapondualwieldweaponname( name ); + alt_name = weaponaltweaponname( name ); + if ( name != "none" ) + { + weapondata[ "clip" ] = newweapondata[ "clip" ] + oldweapondata[ "clip" ]; + weapondata[ "clip" ] = int( min( weapondata[ "clip" ], weaponclipsize( name ) ) ); + weapondata[ "stock" ] = newweapondata[ "stock" ] + oldweapondata[ "stock" ]; + weapondata[ "stock" ] = int( min( weapondata[ "stock" ], weaponmaxammo( name ) ) ); + weapondata[ "fuel" ] = newweapondata[ "fuel" ] + oldweapondata[ "fuel" ]; + weapondata[ "fuel" ] = int( min( weapondata[ "fuel" ], weaponfuellife( name ) ) ); + weapondata[ "heat" ] = int( min( newweapondata[ "heat" ], oldweapondata[ "heat" ] ) ); + weapondata[ "overheat" ] = int( min( newweapondata[ "overheat" ], oldweapondata[ "overheat" ] ) ); + } + if ( dw_name != "none" ) + { + weapondata[ "lh_clip" ] = newweapondata[ "lh_clip" ] + oldweapondata[ "lh_clip" ]; + weapondata[ "lh_clip" ] = int( min( weapondata[ "lh_clip" ], weaponclipsize( dw_name ) ) ); + } + if ( alt_name != "none" ) + { + weapondata[ "alt_clip" ] = newweapondata[ "alt_clip" ] + oldweapondata[ "alt_clip" ]; + weapondata[ "alt_clip" ] = int( min( weapondata[ "alt_clip" ], weaponclipsize( alt_name ) ) ); + weapondata[ "alt_stock" ] = newweapondata[ "alt_stock" ] + oldweapondata[ "alt_stock" ]; + weapondata[ "alt_stock" ] = int( min( weapondata[ "alt_stock" ], weaponmaxammo( alt_name ) ) ); + } + return weapondata; +} + +weapondata_give( weapondata ) //checked matches cerberus output +{ + current = get_player_weapon_with_same_base( weapondata[ "name" ] ); + if ( isDefined( current ) ) + { + curweapondata = get_player_weapondata( self, current ); + self takeweapon( current ); + weapondata = merge_weapons( curweapondata, weapondata ); + } + name = weapondata[ "name" ]; + weapon_give( name, undefined, undefined, 1 ); + dw_name = weapondualwieldweaponname( name ); + alt_name = weaponaltweaponname( name ); + if ( name != "none" ) + { + self setweaponammoclip( name, weapondata[ "clip" ] ); + self setweaponammostock( name, weapondata[ "stock" ] ); + if ( isDefined( weapondata[ "fuel" ] ) ) + { + self setweaponammofuel( name, weapondata[ "fuel" ] ); + } + if ( isDefined( weapondata[ "heat" ] ) && isDefined( weapondata[ "overheat" ] ) ) + { + self setweaponoverheating( weapondata[ "overheat" ], weapondata[ "heat" ], name ); + } + } + if ( dw_name != "none" ) + { + self setweaponammoclip( dw_name, weapondata[ "lh_clip" ] ); + } + if ( alt_name != "none" ) + { + self setweaponammoclip( alt_name, weapondata[ "alt_clip" ] ); + self setweaponammostock( alt_name, weapondata[ "alt_stock" ] ); + } +} + +register_zombie_weapon_callback( str_weapon, func ) //checked matches cerberus output +{ + if ( !isDefined( level.zombie_weapons_callbacks ) ) + { + level.zombie_weapons_callbacks = []; + } + if ( !isDefined( level.zombie_weapons_callbacks[ str_weapon ] ) ) + { + level.zombie_weapons_callbacks[ str_weapon ] = func; + } +} + + + + + + + + + + diff --git a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_zonemgr.gsc b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_zonemgr.gsc index 5ea226f..547f824 100644 --- a/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_zonemgr.gsc +++ b/Plutonium specific gsc-related fixes/18 Player ZM Fixes/maps/mp/zombies/_zm_zonemgr.gsc @@ -686,77 +686,77 @@ create_spawner_list( zkeys ) { if(zone.spawn_locations[ i ].is_enabled) { - level.zombie_spawn_locations[level.zombie_spawn_locations.size] = zone.spawn_locations[i]; + level.zombie_spawn_locations[ level.zombie_spawn_locations.size ] = zone.spawn_locations[ i ]; } } - for(x = 0; x < zone.inert_locations.size; x++) + for ( x = 0; x < zone.inert_locations.size; x++ ) { - if(zone.inert_locations[x].is_enabled) + if ( zone.inert_locations[ x ].is_enabled) { - level.inert_locations[level.inert_locations.size] = zone.inert_locations[x]; + level.inert_locations[ level.inert_locations.size ] = zone.inert_locations[ x ]; } } - for(x = 0; x < zone.dog_locations.size; x++) + for ( x = 0; x < zone.dog_locations.size; x++ ) { - if(zone.dog_locations[x].is_enabled) + if ( zone.dog_locations[ x ].is_enabled ) { - level.enemy_dog_locations[level.enemy_dog_locations.size] = zone.dog_locations[x]; + level.enemy_dog_locations[ level.enemy_dog_locations.size ] = zone.dog_locations[ x ]; } } - for(x = 0; x < zone.screecher_locations.size; x++) + for ( x = 0; x < zone.screecher_locations.size; x++ ) { - if(zone.screecher_locations[x].is_enabled) + if ( zone.screecher_locations[ x ].is_enabled) { - level.zombie_screecher_locations[level.zombie_screecher_locations.size] = zone.screecher_locations[x]; + level.zombie_screecher_locations[ level.zombie_screecher_locations.size ] = zone.screecher_locations[ x ]; } } - for(x = 0; x < zone.avogadro_locations.size; x++) + for ( x = 0; x < zone.avogadro_locations.size; x++ ) { - if(zone.avogadro_locations[x].is_enabled) + if ( zone.avogadro_locations[ x ].is_enabled) { - level.zombie_avogadro_locations[level.zombie_avogadro_locations.size] = zone.avogadro_locations[x]; + level.zombie_avogadro_locations[ level.zombie_avogadro_locations.size ] = zone.avogadro_locations[ x ]; } } - for(x = 0; x < zone.quad_locations.size; x++) + for ( x = 0; x < zone.quad_locations.size; x++ ) { - if(zone.quad_locations[x].is_enabled) + if ( zone.quad_locations[ x ].is_enabled ) { - level.quad_locations[level.quad_locations.size] = zone.quad_locations[x]; + level.quad_locations[ level.quad_locations.size ] = zone.quad_locations[ x ]; } } - for(x = 0; x < zone.leaper_locations.size; x++) + for ( x = 0; x < zone.leaper_locations.size; x++ ) { - if(zone.leaper_locations[x].is_enabled) + if ( zone.leaper_locations[ x ].is_enabled ) { - level.zombie_leaper_locations[level.zombie_leaper_locations.size] = zone.leaper_locations[x]; + level.zombie_leaper_locations[ level.zombie_leaper_locations.size ] = zone.leaper_locations[ x ]; } } - for(x = 0; x < zone.astro_locations.size; x++) + for ( x = 0; x < zone.astro_locations.size; x++ ) { - if(zone.astro_locations[x].is_enabled) + if ( zone.astro_locations[ x ].is_enabled ) { - level.zombie_astro_locations[level.zombie_astro_locations.size] = zone.astro_locations[x]; + level.zombie_astro_locations[ level.zombie_astro_locations.size ] = zone.astro_locations[ x ]; } } - for(x = 0; x < zone.napalm_locations.size; x++) + for ( x = 0; x < zone.napalm_locations.size; x++ ) { - if(zone.napalm_locations[x].is_enabled) + if ( zone.napalm_locations[x].is_enabled ) { - level.zombie_napalm_locations[level.zombie_napalm_locations.size] = zone.napalm_locations[x]; + level.zombie_napalm_locations[ level.zombie_napalm_locations.size ] = zone.napalm_locations[ x ]; } } - for(x = 0; x < zone.brutus_locations.size; x++) + for ( x = 0; x < zone.brutus_locations.size; x++ ) { - if(zone.brutus_locations[x].is_enabled) + if ( zone.brutus_locations[ x ].is_enabled ) { - level.zombie_brutus_locations[level.zombie_brutus_locations.size] = zone.brutus_locations[x]; + level.zombie_brutus_locations[ level.zombie_brutus_locations.size ] = zone.brutus_locations[ x ]; } } - for(x = 0; x < zone.mechz_locations.size; x++) + for ( x = 0; x < zone.mechz_locations.size; x++ ) { - if(zone.mechz_locations[x].is_enabled) + if ( zone.mechz_locations[ x ].is_enabled ) { - level.zombie_mechz_locations[level.zombie_mechz_locations.size] = zone.mechz_locations[x]; + level.zombie_mechz_locations[level.zombie_mechz_locations.size] = zone.mechz_locations[ x ]; } } }