diff --git a/StartWave/Classes/OptionsParser.uc b/StartWave/Classes/OptionsParser.uc new file mode 100644 index 0000000..404cbf7 --- /dev/null +++ b/StartWave/Classes/OptionsParser.uc @@ -0,0 +1,77 @@ +class OptionsParser extends Object; + +const GameInfo = class'GameInfo'; + +/** +*** @brief Gets a int from the launch command if available. +*** +*** @param Options - options passed in via the launch command +*** @param ParseString - the variable we are looking for +*** @param CurrentValue - the current value of the variable +*** @return int value of the option we are looking for +***/ +static function int GetIntOption( string Options, string ParseString, int CurrentValue) +{ + return GameInfo.static.GetIntOption(Options, ParseString, CurrentValue); +} + +/** +*** @brief Gets a bool from the launch command if available. +*** +*** @param Options - options passed in via the launch command +*** @param ParseString - the variable we are looking for +*** @param CurrentValue - the current value of the variable +*** @return bool value of the option we are looking for +***/ +static public function bool GetBoolOption(string Options, string ParseString, bool CurrentValue) +{ + local string InOpt; + + //Find the value associated with this variable in the launch command. + InOpt = GameInfo.static.ParseOption(Options, ParseString); + + if(InOpt != "") + { + return bool(InOpt); + } + + //If a value for this variable was not specified in the launch command, return the original value. + return CurrentValue; +} + +/** +*** @brief Gets a string from the launch command if available. +*** +*** @param Options - options passed in via the launch command +*** @param ParseString - the variable we are looking for +*** @param CurrentValue - the current value of the variable +*** @return string value of the option we are looking for +***/ +static public function string GetStringOption(string Options, string ParseString, string CurrentValue) +{ + local string InOpt; + + //Find the value associated with this variable in the launch command. + InOpt = GameInfo.static.ParseOption(Options, ParseString); + + if(InOpt != "") + { + return InOpt; + } + + //If a value for this variable was not specified in the launch command, return the original value. + return CurrentValue; +} + +/** +*** @brief Gets a LogLevel from the launch command if available. +*** +*** @param Options - options passed in via the launch command +*** @param ParseString - the variable we are looking for +*** @param CurrentValue - the current value of the variable +*** @return E_LogLevel value of the option we are looking for +***/ +static public function E_LogLevel GetLogLevelOption(string Options, string ParseString, E_LogLevel CurrentValue) +{ + return CurrentValue; // TODO: impl +} \ No newline at end of file diff --git a/StartWave/Classes/StartWave.uc b/StartWave/Classes/StartWave.uc index 0a960c9..4162061 100644 --- a/StartWave/Classes/StartWave.uc +++ b/StartWave/Classes/StartWave.uc @@ -1,6 +1,14 @@ -class StartWave extends KFMutator +class StartWave extends Info config(StartWave); +const OptionsParser = class'OptionsParser'; + +var private KFGameInfo KFGI; +var private KFGameInfo_Survival KFGIS; +var private KFGameInfo_Endless KFGIE; + +var private KFGameReplicationInfo KFGRI; + /********************************************************************************************************* * Config properties *********************************************************************************************************/ @@ -37,29 +45,71 @@ var bool bOverridenDifficultySettings; /** Whether the trader duration has been overriden. */ var bool bOverridenTraderDuration; -function InitMutator(string Options, out string ErrorMessage) +public simulated function bool SafeDestroy() { - //This needs to be called first since KFMutator.InitMutator sets the MyKFGI reference. - Super.InitMutator(Options, ErrorMessage); + `Log_Trace(); + + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public event PreBeginPlay() +{ + `Log_Trace(); + + if (WorldInfo.NetMode == NM_Client) + { + `Log_Fatal("Wrong NetMode:" @ WorldInfo.NetMode); + SafeDestroy(); + return; + } + + Super.PreBeginPlay(); + + PreInit(); +} + +public event PostBeginPlay() +{ + `Log_Trace(); + + if (bPendingDelete || bDeleteMe) return; + + Super.PostBeginPlay(); + + PostInit(); +} + +private function PreInit() +{ + local String Options; + + `Log_Trace(); + + Options = WorldInfo.GetLocalURL(); //Parse options entered via the launch command. //We further restrict StartWave later when we know the maximum wave number for the selected game length. - StartWave = Max(class'GameInfo'.static.GetIntOption(Options, "StartWave", StartWave), 1); - InitialTraderTime = Max(class'GameInfo'.static.GetIntOption(Options, "InitialTraderTime", - InitialTraderTime), 1); - TraderTime = Max(class'GameInfo'.static.GetIntOption(Options, "TraderTime", TraderTime), 1); - Dosh = Max(class'GameInfo'.static.GetIntOption(Options, "Dosh", Dosh), 0); - Boss = class'GameInfo'.static.GetIntOption(Options, "Boss", Boss); - bStartWithTrader = GetBoolOption(Options, "bStartWithTrader", bStartWithTrader); - LogLevel = E_LogLevel(class'GameInfo'.static.GetIntOption(Options, "LogLevel", LogLevel)); + StartWave = OptionsParser.static.GetIntOption (Options, "StartWave", StartWave); + InitialTraderTime = OptionsParser.static.GetIntOption (Options, "InitialTraderTime", InitialTraderTime); + TraderTime = OptionsParser.static.GetIntOption (Options, "TraderTime", TraderTime); + Dosh = OptionsParser.static.GetIntOption (Options, "Dosh", Dosh); + Boss = OptionsParser.static.GetIntOption (Options, "Boss", Boss); + bStartWithTrader = OptionsParser.static.GetBoolOption (Options, "bStartWithTrader", bStartWithTrader); + LogLevel = OptionsParser.static.GetLogLevelOption(Options, "LogLevel", LogLevel); + + // Adjust values if needed + StartWave = Max(StartWave, 1); + InitialTraderTime = Max(InitialTraderTime, 1); + TraderTime = Max(TraderTime, 1); + Dosh = Max(Dosh, 0); //DEBUG - `Log_Debug("StartWave: " $ StartWave); - `Log_Debug("InitialTraderTime: " $ InitialTraderTime); - `Log_Debug("TraderTime: " $ TraderTime); - `Log_Debug("Dosh: " $ Dosh); - `Log_Debug("Boss: " $ Boss); - `Log_Debug("bStartWithTrader: " $ bStartWithTrader); + `Log_Debug("StartWave:" @ StartWave); + `Log_Debug("InitialTraderTime:" @ InitialTraderTime); + `Log_Debug("TraderTime:" @ TraderTime); + `Log_Debug("Dosh:" @ Dosh); + `Log_Debug("Boss:" @ Boss); + `Log_Debug("bStartWithTrader:" @ bStartWithTrader); bOverridenDifficultySettings = false; bOverridenTraderDuration = false; @@ -67,7 +117,7 @@ function InitMutator(string Options, out string ErrorMessage) SetTimer(0.1, false, nameof(OverrideTimer)); //Override the boss with the boss corresponding to the specified boss index. -1 signifies random. - if(Boss != -1) + if (Boss != -1) { SetTimer(0.1, false, nameof(OverrideBoss)); } @@ -78,26 +128,50 @@ function InitMutator(string Options, out string ErrorMessage) bInitialTrader = bStartWithTrader; //If we want to start with the trader active or alter the starting wave number. - if(bStartWithTrader || StartWave > 1) + if (bStartWithTrader || StartWave > 1) { `Log_Debug("Calling StartWaveTimer() to alter the start wave or activate the trader initially."); SetTimer(0.2, false, nameof(StartWaveTimer)); } //If we will need to alter TimeBetweenWaves for later activations of the trader. - if(bStartWithTrader && InitialTraderTime != TraderTime) + if (bStartWithTrader && InitialTraderTime != TraderTime) { `Log_Debug("Calling UpdateTraderDurationTimer() to alter the trader duration later."); SetTimer(1, true, nameof(UpdateTraderDurationTimer)); } } +private function PostInit() +{ + `Log_Trace(); + + KFGI = KFGameInfo(WorldInfo.Game); + if (KFGIS == None) + { + `Log_Fatal("Incompatible gamemode:" @ WorldInfo.Game $ ". Destroy..."); + SafeDestroy(); + return; + } + + KFGIS = KFGameInfo_Survival(KFGI); + if (KFGIS == None) + { + `Log_Warn("The game mode does not extend KFGameInfo_Survival. Most features of this mutator are not compatible with non-wave-based game modes."); + } + + KFGIE = KFGameInfo_Endless(KFGIS); + KFGRI = KFGI.MyKFGRI; +} + /** Allows for handling player input in the console by the mutator. */ -function Mutate(string MutateString, PlayerController Sender) +public function Mutate(string MutateString, PlayerController Sender) { local array CommandBreakdown; - if(MutateString == "") + `Log_Trace(); + + if (MutateString == "") { return; } @@ -106,13 +180,15 @@ function Mutate(string MutateString, PlayerController Sender) ParseStringIntoArray(MutateString, CommandBreakdown, " ", true); //The CheatManager check is equivalent to checking if cheats are enabled for that player. - if(CommandBreakdown.Length > 1 && CommandBreakdown[0] == "setwave" && Sender.CheatManager != None && - MyKFGI.GetLivingPlayerCount() > 0) + if (CommandBreakdown.Length > 1&& + CommandBreakdown[0] == "setwave" && + Sender.CheatManager != None && + KFGI.GetLivingPlayerCount() > 0) { //The setwave command should be: mutate setwave WaveNum bSkipTraderTime //where WaveNum is an integer (or byte) and bSkipTraderTime is a bool. - if(CommandBreakdown.Length == 2) + if (CommandBreakdown.Length == 2) { SetWave(int(CommandBreakdown[1]), Sender); } @@ -121,23 +197,23 @@ function Mutate(string MutateString, PlayerController Sender) SetWave(int(CommandBreakdown[1]), Sender, bool(CommandBreakdown[2])); } } - - Super.Mutate(MutateString, Sender); } /** Jumps to the specified wave, NewWaveNum, with trader time iff bSkipTraderTime is false. */ -function SetWave(int NewWaveNum, PlayerController PC, optional bool bSkipTraderTime) +private function SetWave(int NewWaveNum, PlayerController PC, optional bool bSkipTraderTime) { - if(NewWaveNum < 1) + `Log_Trace(); + + if (NewWaveNum < 1) { `Log_Error("SetWave: new wave num must be > 0."); return; } - if(KFGameInfo_Endless(MyKFGI) != None) + if (KFGIE != None) { //Jump straight to the final wave if the specified wave number is higher than wave max. - if(NewWaveNum > 254) + if (NewWaveNum > 254) { NewWaveNum = 254; } @@ -145,83 +221,87 @@ function SetWave(int NewWaveNum, PlayerController PC, optional bool bSkipTraderT else { //Jump straight to the boss wave if the specified wave number is higher than wave max. - if(NewWaveNum > KFGameInfo_Survival(MyKFGI).WaveMax) + if (NewWaveNum > KFGameInfo_Survival(KFGI).WaveMax) { - NewWaveNum = KFGameInfo_Survival(MyKFGI).WaveMax+1; + NewWaveNum = KFGameInfo_Survival(KFGI).WaveMax+1; } } - KFGameInfo_Survival(MyKFGI).WaveNum = NewWaveNum - 1; + if (KFGIS != None) + { + KFGIS.WaveNum = NewWaveNum - 1; + } //Kill all zeds currently alive. PC.ConsoleCommand("KillZeds"); //Clear any current objectives. - MyKFGI.MyKFGRI.DeactivateObjective(); + KFGRI.DeactivateObjective(); - if(bSkipTraderTime) + if (bSkipTraderTime) { //Go to some unused state so that PlayingWave.BeginState is called when we go to PlayingWave. - MyKFGI.GotoState('TravelTheWorld'); + KFGI.GotoState('TravelTheWorld'); UpdateEndlessDifficulty(); //Go to PlayingWave to start the new wave. - MyKFGI.GotoState('PlayingWave'); + KFGI.GotoState('PlayingWave'); } else { //Go to trader time before starting the new wave. - MyKFGI.GotoState('TraderOpen'); + KFGI.GotoState('TraderOpen'); UpdateEndlessDifficulty(); } - MyKFGI.ResetAllPickups(); + KFGI.ResetAllPickups(); } /** *** Since the difficulty in Endless scales with the wave number, we need to update the difficulty when *** jumping between wave numbers to match the expected difficulty. ***/ -function UpdateEndlessDifficulty() +private function UpdateEndlessDifficulty() { - local KFGameInfo_Endless Endless; local int i; - Endless = KFGameInfo_Endless(MyKFGI); + `Log_Trace(); - if(Endless == None) + if (KFGIE == None) { return; } //Reflects the difficulty update in KFGameInfo_Endless.SetWave. - Endless.bIsInHoePlus = false; - Endless.ResetDifficulty(); - Endless.SpawnManager.GetWaveSettings(Endless.SpawnManager.WaveSettings); - Endless.UpdateGameSettings(); + KFGIE.bIsInHoePlus = false; + KFGIE.ResetDifficulty(); + KFGIE.SpawnManager.GetWaveSettings(KFGIE.SpawnManager.WaveSettings); + KFGIE.UpdateGameSettings(); //Don't bother iterating for i=0-4, no difficulty increment can occur. - for(i = 5; i < Endless.WaveNum; ++i) + for (i = 5; i < KFGIE.WaveNum; ++i) { //Simulate the death of a boss. The difficulty is incremented after each boss round. - if(i % 5 == 0) + if (i % 5 == 0) { - Endless.IncrementDifficulty(); + KFGIE.IncrementDifficulty(); } //This should happen at the end of each wave (if we're in HoE+). The check is handled internally. //We do this after the simulation of a boss death so that bIsInHoePlus can be set first. - Endless.HellOnEarthPlusRoundIncrement(); + KFGIE.HellOnEarthPlusRoundIncrement(); } } /** Checks whether we should force the initial trader, regardless of the config/command value. */ -function CheckForceInitialTrader() +private function CheckForceInitialTrader() { + `Log_Trace(); + //Force the initial trader for compatibility with holdout maps. Otherwise, zeds spawn in the wrong room. - if(!bStartWithTrader && StartWave > 1) + if (!bStartWithTrader && StartWave > 1) { bStartWithTrader = true; InitialTraderTime = 1.0; @@ -229,13 +309,15 @@ function CheckForceInitialTrader() } /** Overrides the boss to spawn if a valid boss index has been specified. */ -function OverrideBoss() +private function OverrideBoss() { local bool bHalt; local byte MaxIters, i, MaxSameIters, PrevIndex, SameIters; + `Log_Trace(); + //We need a valid KFGRI reference as we use its public BossIndex field. - if(MyKFGI.MyKFGRI == None) + if (KFGRI == None) { SetTimer(0.2, false, nameof(OverrideBoss)); return; @@ -254,33 +336,33 @@ function OverrideBoss() //while we assume the index is forced, in which case we can't do anything about it. SameIters = 0; MaxSameIters = 10; - PrevIndex = MyKFGI.MyKFGRI.BossIndex; + PrevIndex = KFGRI.BossIndex; - bHalt = Boss < 0 || MyKFGI.MyKFGRI.BossIndex == Boss; + bHalt = Boss < 0 || KFGRI.BossIndex == Boss; - while(!bHalt) + while (!bHalt) { ++i; //Randomly select a new boss. - MyKFGI.SetBossIndex(); + KFGI.SetBossIndex(); //Track whether the boss index is changing. - if(MyKFGI.MyKFGRI.BossIndex == PrevIndex) + if (KFGRI.BossIndex == PrevIndex) { ++SameIters; } else { SameIters = 0; - PrevIndex = MyKFGI.MyKFGRI.BossIndex; + PrevIndex = KFGRI.BossIndex; } //Halt if we have the desired index or we have tried enough times. - bHalt = MyKFGI.MyKFGRI.BossIndex == Boss || SameIters >= MaxSameIters || i >= MaxIters; + bHalt = KFGRI.BossIndex == Boss || SameIters >= MaxSameIters || i >= MaxIters; } - if(MyKFGI.MyKFGRI.BossIndex == Boss) + if (KFGRI.BossIndex == Boss) { `Log_Debug("Successfully overrode boss index to" @ Boss @ "after" @ i @ "attempts."); } @@ -291,41 +373,40 @@ function OverrideBoss() } /** Overrides difficulty settings and trader duration when possible. */ -function OverrideTimer() +private function OverrideTimer() { - local KFGameInfo_Survival KFGI_Surv; - local KFGameInfo_Endless KFGI_Endl; - local KFGameDifficulty_Endless KFGD_Endl; + local KFGameDifficulty_Endless KFGDE; local int i; + `Log_Trace(); + //If we've overriden what we need to, don't call this timer again. - if(bOverridenDifficultySettings && bOverridenTraderDuration) + if (bOverridenDifficultySettings && bOverridenTraderDuration) { `Log_Debug("All settings have been overriden."); return; } - if(!bOverridenDifficultySettings && MyKFGI.DifficultyInfo != None) + if (!bOverridenDifficultySettings && KFGI.DifficultyInfo != None) { `Log_Debug("Overriding difficulty settings..."); bOverridenDifficultySettings = true; //Override starting dosh. - MyKFGI.DifficultyInfo.Normal.StartingDosh = Dosh; - MyKFGI.DifficultyInfo.Hard.StartingDosh = Dosh; - MyKFGI.DifficultyInfo.Suicidal.StartingDosh = Dosh; - MyKFGI.DifficultyInfo.HellOnEarth.StartingDosh = Dosh; + KFGI.DifficultyInfo.Normal.StartingDosh = Dosh; + KFGI.DifficultyInfo.Hard.StartingDosh = Dosh; + KFGI.DifficultyInfo.Suicidal.StartingDosh = Dosh; + KFGI.DifficultyInfo.HellOnEarth.StartingDosh = Dosh; - KFGI_Endl = KFGameInfo_Endless(MyKFGI); - if (KFGI_Endl != None) + if (KFGIE != None) { - KFGD_Endl = KFGameDifficulty_Endless(KFGI_Endl.DifficultyInfo); - if (KFGD_Endl != None) + KFGDE = KFGameDifficulty_Endless(KFGIE.DifficultyInfo); + if (KFGDE != None) { - for (i = 0; i < KFGD_Endl.CurrentDifficultyScaling.Difficulties.length; ++i) + for (i = 0; i < KFGDE.CurrentDifficultyScaling.Difficulties.length; ++i) { - KFGD_Endl.CurrentDifficultyScaling.Difficulties[i].StartingDosh = Dosh; + KFGDE.CurrentDifficultyScaling.Difficulties[i].StartingDosh = Dosh; } } } @@ -334,19 +415,17 @@ function OverrideTimer() //We need to set the difficulty settings again - normally done in KFGameInfo.InitGame - to apply //these changes, since this happens after InitGame is executed. - MyKFGI.DifficultyInfo.SetDifficultySettings(MyKFGI.GameDifficulty); + KFGI.DifficultyInfo.SetDifficultySettings(KFGI.GameDifficulty); } //Set the starting wave number. - if(!bOverridenTraderDuration) + if (!bOverridenTraderDuration) { - KFGI_Surv = KFGameInfo_Survival(MyKFGI); - - if(KFGI_Surv != None) + if (KFGIS != None) { //We require the SpawnManager to be set, because this signifies that InitSpawnManager has been //executed, which sets WaveMax. - if(MyKFGI.SpawnManager != None) + if (KFGI.SpawnManager != None) { `Log_Debug("Overriding trader duration..."); @@ -355,13 +434,13 @@ function OverrideTimer() //Since InitSpawnManager has been executed, then PreBeginPlay must have been executed. This //means that PostBeginPlay will have been executed as well since it happens straight after. //Now we can override TimeBetweenWaves. - KFGI_Surv.TimeBetweenWaves = bInitialTrader ? InitialTraderTime : TraderTime; + KFGIS.TimeBetweenWaves = bInitialTrader ? InitialTraderTime : TraderTime; - `Log_Debug("Trader duration has been set to:" @ KFGI_Surv.TimeBetweenWaves @ "seconds."); + `Log_Debug("Trader duration has been set to:" @ KFGIS.TimeBetweenWaves @ "seconds."); } else { - `Log_Debug("MyKFGI.SpawnManager hasn't been set yet. Calling StartWaveTimer again."); + `Log_Debug("KFGI.SpawnManager hasn't been set yet. Calling StartWaveTimer again."); //We don't know WaveMax yet, so we need to wait longer. SetTimer(0.1, false, nameof(StartWaveTimer)); @@ -378,22 +457,21 @@ function OverrideTimer() SetTimer(0.1, false, nameof(OverrideTimer)); } -function StartWaveTimer() +private function StartWaveTimer() { - local KFGameInfo_Survival KFGI_Surv; local PlayerController PC; + `Log_Trace(); + //We need to wait for the wave to be active, as this will signify that StartMatch has been executed. - if(!MyKFGI.IsWaveActive()) + if (!KFGI.IsWaveActive()) { //If the wave isn't active yet (probably still in lobby), wait. SetTimer(0.1, false, nameof(StartWaveTimer)); return; } - KFGI_Surv = KFGameInfo_Survival(MyKFGI); - - if(KFGI_Surv == None) + if (KFGIS == None) { return; } @@ -412,50 +490,52 @@ function StartWaveTimer() //Set the starting wave number. //Keep the assignments separated so that we can used the restricted StartWave later if we want. - StartWave = Min(StartWave, KFGI_Surv.WaveMax); + StartWave = Min(StartWave, KFGIS.WaveMax); //We need to subtract 1 because when the state is eventually reset to PlayingWave, this will be //incremented by 1. - KFGI_Surv.WaveNum = StartWave - 1; + KFGIS.WaveNum = StartWave - 1; - `Log_Debug("WaveNum set to:" @ KFGI_Surv.WaveNum); + `Log_Debug("WaveNum set to:" @ KFGIS.WaveNum); - if(bStartWithTrader) + if (bStartWithTrader) { `Log_Debug("Switching to state: TraderOpen."); //We need to update GRI's WaveNum and update the HUD element that shows the last wave. - MyKFGI.MyKFGRI.WaveNum = KFGI_Surv.WaveNum; - MyKFGI.MyKFGRI.UpdateHUDWaveCount(); + KFGRI.WaveNum = KFGIS.WaveNum; + KFGRI.UpdateHUDWaveCount(); //Start with the trader active. - MyKFGI.GotoState('TraderOpen', 'Begin'); + KFGI.GotoState('TraderOpen', 'Begin'); } else { `Log_Debug("Switching to state: PlayingWave."); //Start with a wave as usual - but our StartWave number will be used. - MyKFGI.GotoState('PlayingWave'); + KFGI.GotoState('PlayingWave'); } //Since we've updated the wave number, we need to update the game settings (which includes the //current wave number). - MyKFGI.UpdateGameSettings(); + KFGI.UpdateGameSettings(); bInitialTrader = false; } /** Updates the trader duration. Waits until the initial trader has closed. */ -function UpdateTraderDurationTimer() +private function UpdateTraderDurationTimer() { + `Log_Trace(); + //If the initial trader has already been opened, and the wave is now active. - if(!bInitialTrader && MyKFGI.IsWaveActive()) + if (!bInitialTrader && KFGI.IsWaveActive()) { - if(KFGameInfo_Survival(MyKFGI) != None) + if (KFGameInfo_Survival(KFGI) != None) { `Log_Debug("Updating trader duration to" @ TraderTime @ "seconds."); //We can update TimeBetweenWaves to be the TraderTime we specified in the launch command. - KFGameInfo_Survival(MyKFGI).TimeBetweenWaves = TraderTime; + KFGameInfo_Survival(KFGI).TimeBetweenWaves = TraderTime; } else { @@ -467,50 +547,7 @@ function UpdateTraderDurationTimer() } } -/** -*** @brief Gets a bool from the launch command if available. -*** -*** @param Options - options passed in via the launch command -*** @param ParseString - the variable we are looking for -*** @param CurrentValue - the current value of the variable -*** @return bool value of the option we are looking for -***/ -static function bool GetBoolOption(string Options, string ParseString, bool CurrentValue) +defaultproperties { - local string InOpt; - //Find the value associated with this variable in the launch command. - InOpt = class'GameInfo'.static.ParseOption(Options, ParseString); - - if(InOpt != "") - { - return bool(InOpt); - } - - //If a value for this variable was not specified in the launch command, return the original value. - return CurrentValue; -} - -/** -*** @brief Gets a string from the launch command if available. -*** -*** @param Options - options passed in via the launch command -*** @param ParseString - the variable we are looking for -*** @param CurrentValue - the current value of the variable -*** @return string value of the option we are looking for -***/ -static function string GetStringOption(string Options, string ParseString, string CurrentValue) -{ - local string InOpt; - - //Find the value associated with this variable in the launch command. - InOpt = class'GameInfo'.static.ParseOption(Options, ParseString); - - if(InOpt != "") - { - return InOpt; - } - - //If a value for this variable was not specified in the launch command, return the original value. - return CurrentValue; } \ No newline at end of file diff --git a/StartWave/Classes/StartWaveMut.uc b/StartWave/Classes/StartWaveMut.uc new file mode 100644 index 0000000..24710e6 --- /dev/null +++ b/StartWave/Classes/StartWaveMut.uc @@ -0,0 +1,53 @@ +class StartWaveMut extends KFMutator; + +var private StartWave StartWave; + +public simulated function bool SafeDestroy() +{ + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public event PreBeginPlay() +{ + Super.PreBeginPlay(); + + if (WorldInfo.NetMode == NM_Client) return; + + foreach WorldInfo.DynamicActors(class'StartWave', StartWave) + { + break; + } + + if (StartWave == None) + { + StartWave = WorldInfo.Spawn(class'StartWave'); + } + + if (StartWave == None) + { + `Log_Base("FATAL: Can't Spawn 'StartWave'"); + SafeDestroy(); + } +} + +public function AddMutator(Mutator Mut) +{ + if (Mut == Self || bPendingDelete || bDeleteMe) return; + + if (Mut.Class == Class) + StartWaveMut(Mut).SafeDestroy(); + else + Super.AddMutator(Mut); +} + +public function Mutate(String MutateString, PlayerController Sender) +{ + StartWave.Mutate(MutateString, Sender); + + Super.Mutate(MutateString, Sender); +} + +defaultproperties +{ + +} \ No newline at end of file