From f9c9cde5e1d92ae17e7daf698f2a6cf2738e2be0 Mon Sep 17 00:00:00 2001 From: Anton Tarasenko Date: Tue, 6 Sep 2022 03:37:08 +0700 Subject: [PATCH] Add wave component and `ASquad` object --- .../KillingFloor/Frontend/KFFrontend.uc | 9 + .../KillingFloor/Frontend/Waves/ASquad.uc | 116 +++++++++ .../Frontend/Waves/AWavesComponent.uc | 25 ++ sources/Gameplay/KF1Frontend/KF1_Frontend.uc | 1 + .../Gameplay/KF1Frontend/Waves/AKF1_Squad.uc | 237 ++++++++++++++++++ .../KF1Frontend/Waves/KF1_WavesComponent.uc | 24 ++ 6 files changed, 412 insertions(+) create mode 100644 sources/Gameplay/BaseClasses/KillingFloor/Frontend/Waves/ASquad.uc create mode 100644 sources/Gameplay/BaseClasses/KillingFloor/Frontend/Waves/AWavesComponent.uc create mode 100644 sources/Gameplay/KF1Frontend/Waves/AKF1_Squad.uc create mode 100644 sources/Gameplay/KF1Frontend/Waves/KF1_WavesComponent.uc diff --git a/sources/Gameplay/BaseClasses/KillingFloor/Frontend/KFFrontend.uc b/sources/Gameplay/BaseClasses/KillingFloor/Frontend/KFFrontend.uc index 1c5be1b..ebd3eb0 100644 --- a/sources/Gameplay/BaseClasses/KillingFloor/Frontend/KFFrontend.uc +++ b/sources/Gameplay/BaseClasses/KillingFloor/Frontend/KFFrontend.uc @@ -23,6 +23,9 @@ class KFFrontend extends BaseFrontend var private config class tradingClass; var public ATradingComponent trading; +var private config class wavesClass; +var public AWavesComponent waves; + var private config class healthClass; var public AHealthComponent health; @@ -32,6 +35,9 @@ protected function Constructor() if (tradingClass != none) { trading = ATradingComponent(_.memory.Allocate(tradingClass)); } + if (wavesClass != none) { + waves = AWavesComponent(_.memory.Allocate(wavesClass)); + } if (healthClass != none) { health = AHealthComponent(_.memory.Allocate(healthClass)); } @@ -40,8 +46,10 @@ protected function Constructor() protected function Finalizer() { _.memory.Free(trading); + _.memory.Free(waves); _.memory.Free(health); trading = none; + waves = none; health = none; } @@ -62,5 +70,6 @@ public function EItemTemplateInfo GetItemTemplateInfo(BaseText templateName) defaultproperties { tradingClass = none + wavesClass = none healthClass = none } \ No newline at end of file diff --git a/sources/Gameplay/BaseClasses/KillingFloor/Frontend/Waves/ASquad.uc b/sources/Gameplay/BaseClasses/KillingFloor/Frontend/Waves/ASquad.uc new file mode 100644 index 0000000..4cb8624 --- /dev/null +++ b/sources/Gameplay/BaseClasses/KillingFloor/Frontend/Waves/ASquad.uc @@ -0,0 +1,116 @@ +/** + * Object that is meant to describe a squad of zeds for Killing Floor spawning + * system. Zeds can be either added individually or through native squad + * definitions "3A1B2D1G1H". + * Copyright 2022 Anton Tarasenko + *------------------------------------------------------------------------------ + * This file is part of Acedia. + * + * Acedia is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, or + * (at your option) any later version. + * + * Acedia is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Acedia. If not, see . + */ +class ASquad extends AcediaObject; + +struct ZedCountPair +{ + var Text template; + var int count; +}; + +/** + * Resets caller squad, removing all zeds inside. + */ +public function Reset(); + +/** + * Changes amount of zeds with given template inside the caller squad. + * + * @param template Template for which to change stored count. + * @param delta By how much to change zed count in squad. Negative + * values are allowed. + */ +public function ChangeCount(BaseText template, int delta); + +/** + * Changes amount of zeds with given template inside the caller squad. + * + * @param template Template for which to change stored count. + * @param delta By how much to change zed count in squad. Negative + * values are allowed. + */ +public final function ChangeCount_S(string template, int delta) +{ + local MutableText wrapper; + + wrapper = _.text.FromStringM(template); + ChangeCount(wrapper, delta); + wrapper.FreeSelf(); +} + +/** + * Adds zeds into the squad from the text definition format. + * + * For example "3clot5crawer1fp" will add 3 clots, 5 crawlers and 1 fleshpound + * into the squad (names are resolved via entity aliases). + * Counts inside a definition cannot be negative. + * + * @param definition Text definition of the addition to squad. + */ +public function AddFromDefinition(BaseText definition); + +/** + * Adds zeds into the squad from the text definition format. + * + * For example "3clot5crawer1fp" will add 3 clots, 5 crawlers and 1 fleshpound + * into the squad (names are resolved via entity aliases). + * Counts inside a definition cannot be negative. + * + * @param definition Text definition of the addition to squad. + */ +public final function AddFromDefinition_S(string definition) +{ + local MutableText wrapper; + + wrapper = _.text.FromStringM(definition); + AddFromDefinition(wrapper); + wrapper.FreeSelf(); +} + +/** + * Returns list of zeds inside caller squad as an array of zed template and + * the count of that zed in a squad. + * + * @return Array of pairs of template and corresponding zed count inside + * a squad. Guaranteed that there cannot be two array elements with + * the same template. + */ +public function array GetZedList(); + +/** + * Returns amount of zeds of the given template inside the caller squad. + * + * @return Current amount of zeds of the given template inside the caller + * squad. + */ +public function int GetZedCount(BaseText template); + +/** + * Returns current total zed count inside a squad. + * + * @return Current total zed count inside a caller squad. + */ +public function int GetTotalZedCount(); + +defaultproperties +{ +} \ No newline at end of file diff --git a/sources/Gameplay/BaseClasses/KillingFloor/Frontend/Waves/AWavesComponent.uc b/sources/Gameplay/BaseClasses/KillingFloor/Frontend/Waves/AWavesComponent.uc new file mode 100644 index 0000000..9a4c2cf --- /dev/null +++ b/sources/Gameplay/BaseClasses/KillingFloor/Frontend/Waves/AWavesComponent.uc @@ -0,0 +1,25 @@ +/** + * Subset of functionality for dealing with everything related to traders. + * Copyright 2021 - 2022 Anton Tarasenko + *------------------------------------------------------------------------------ + * This file is part of Acedia. + * + * Acedia is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, or + * (at your option) any later version. + * + * Acedia is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Acedia. If not, see . + */ +class AWavesComponent extends AcediaObject + abstract; + +defaultproperties +{ +} \ No newline at end of file diff --git a/sources/Gameplay/KF1Frontend/KF1_Frontend.uc b/sources/Gameplay/KF1Frontend/KF1_Frontend.uc index 8d43e54..7386f75 100644 --- a/sources/Gameplay/KF1Frontend/KF1_Frontend.uc +++ b/sources/Gameplay/KF1Frontend/KF1_Frontend.uc @@ -36,5 +36,6 @@ defaultproperties templatesClass = class'KF1_TemplatesComponent' worldClass = class'KF1_WorldComponent' tradingClass = class'KF1_TradingComponent' + wavesClass = class'KF1_WavesComponent' healthClass = class'KF1_HealthComponent' } \ No newline at end of file diff --git a/sources/Gameplay/KF1Frontend/Waves/AKF1_Squad.uc b/sources/Gameplay/KF1Frontend/Waves/AKF1_Squad.uc new file mode 100644 index 0000000..cb7edf4 --- /dev/null +++ b/sources/Gameplay/KF1Frontend/Waves/AKF1_Squad.uc @@ -0,0 +1,237 @@ +/** + * `ASquad`'s implementation for `KF1_Frontend`. + * Copyright 2022 Anton Tarasenko + *------------------------------------------------------------------------------ + * This file is part of Acedia. + * + * Acedia is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, or + * (at your option) any later version. + * + * Acedia is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Acedia. If not, see . + */ +class AKF1_Squad extends ASquad; + +struct KF1_ZedCountPair +{ + var class zedClass; + var int count; +}; +var array squadZeds; + +protected function Finalizer() +{ + Reset(); +} + +public function Reset() +{ + squadZeds.length = 0; +} + +public function ChangeCount(BaseText template, int delta) +{ + local int pairIndex; + local class templateClass; + + templateClass = class(_.memory.LoadClass(template)); + if (templateClass == none) { + return; + } + pairIndex = FindPairIndex(templateClass, true); + squadZeds[pairIndex].count += delta; + if (squadZeds[pairIndex].count <= 0) { + squadZeds.Remove(pairIndex, 1); + } +} + +private function int FindPairIndex( + class zedClass, + optional bool createIfMissing) +{ + local int i; + local KF1_ZedCountPair newPair; + + for (i = 0; i < squadZeds.length; i += 1) + { + if (squadZeds[i].zedClass == zedClass) { + return i; + } + } + if (createIfMissing) + { + newPair.zedClass = zedClass; + squadZeds[squadZeds.length] = newPair; + return (squadZeds.length - 1); + } + return -1; +} + +public function AddFromDefinition(BaseText definition) +{ + local int index, nextCount; + local Text nextTemplate; + local MutableText numericPart, idPart; + local BaseText.Character nextCharacter; + + if (definition == none) { + return; + } + while (index < definition.GetLength()) + { + numericPart = _.text.Empty(); + idPart = _.text.Empty(); + nextCharacter = definition.GetCharacter(index); + while ( index < definition.GetLength() + && _.text.IsDigit(nextCharacter)) + { + numericPart.AppendCharacter(nextCharacter); + index += 1; + nextCharacter = definition.GetCharacter(index); + } + while ( index < definition.GetLength() + && _.text.IsDigit(nextCharacter)) + { + idPart.AppendCharacter(nextCharacter); + index += 1; + nextCharacter = definition.GetCharacter(index); + } + nextTemplate = ReadTemplateFromZedID(idPart); + nextCount = int(numericPart.ToString()); + ChangeCount(nextTemplate, nextCount); + _.memory.Free(nextTemplate); + _.memory.Free(idPart); + _.memory.Free(numericPart); + } +} + +private function Text ReadTemplateFromZedID(BaseText zedID) +{ + local Text result; + + if (zedID == none) { + return none; + } + result = _.alias.ResolveEntity(zedID); + if (result == none) { + result = TryLoadingFromMID(zedID); + } + return result; +} + +private function Text TryLoadingFromMID(BaseText zedID) +{ + if (_server.unreal.GetKFGameType().kfGameLength != 3) { // `GL_Custom == 3` + return TryLoadingFromMID_Collection(zedId); + } + return TryLoadingFromMID_GameType(zedId); +} + +// Assumes `zedID != none`. +private function Text TryLoadingFromMID_Collection(BaseText zedID) +{ + local int i; + local string zedIDasString; + local array monsterClasses; + + zedIDasString = zedID.ToString(); + if (zedIDasString == "") { + return none; + } + monsterClasses = _server.unreal + .GetKFGameType() + .monsterCollection.default.monsterClasses; + for (i = 0; i < monsterClasses.Length; i += 1) + { + if (monsterClasses[i].mid == zedIDasString) { + return _.text.FromString(monsterClasses[i].mClassName); + } + } + return none; +} + +// Assumes `zedID != none`. +private function Text TryLoadingFromMID_GameType(BaseText zedID) +{ + local int i; + local string zedIDasString; + local array monsterClasses; + + zedIDasString = zedID.ToString(); + if (zedIDasString == "") { + return none; + } + monsterClasses = _server.unreal + .GetKFGameType() + .monsterClasses; + for (i = 0; i < monsterClasses.Length; i += 1) + { + if (monsterClasses[i].mid == zedIDasString) { + return _.text.FromString(monsterClasses[i].mClassName); + } + } + return none; +} + +/** + * Returns list of zeds inside caller squad in a native for KF1 format: + * as pairs of `class` and their counts. + * + * @return Array of pairs `class` and corresponding zed count inside + * a squad. Guaranteed that there cannot be two array elements with + * the same class. + */ +public function array GetNativeZedList() +{ + return squadZeds; +} + +public function array GetZedList() +{ + local int i; + local ZedCountPair nextPair; + local array result; + + for (i = 0; i < squadZeds.length; i += 1) + { + nextPair.template = _.text.FromClass(squadZeds[i].zedClass); + nextPair.count = squadZeds[i].count; + result[result.length] = nextPair; + } + return result; +} + +public function int GetZedCount(BaseText template) +{ + local int pairIndex; + local class templateClass; + + templateClass = class(_.memory.LoadClass(template)); + pairIndex = FIndPairIndex(templateClass); + if (pairIndex < 0) { + return 0; + } + return squadZeds[pairIndex].count; +} + +public function int GetTotalZedCount() +{ + local int i; + local int totalCount; + + for (i = 0; i < squadZeds.length; i += 1) { + totalCount += squadZeds[i].count; + } + return totalCount; +} + +defaultproperties +{ +} \ No newline at end of file diff --git a/sources/Gameplay/KF1Frontend/Waves/KF1_WavesComponent.uc b/sources/Gameplay/KF1Frontend/Waves/KF1_WavesComponent.uc new file mode 100644 index 0000000..34cbef6 --- /dev/null +++ b/sources/Gameplay/KF1Frontend/Waves/KF1_WavesComponent.uc @@ -0,0 +1,24 @@ +/** + * `AWavesComponent`'s implementation for `KF1_Frontend`. + * Copyright 2022 Anton Tarasenko + *------------------------------------------------------------------------------ + * This file is part of Acedia. + * + * Acedia is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, or + * (at your option) any later version. + * + * Acedia is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Acedia. If not, see . + */ +class KF1_WavesComponent extends AWavesComponent; + +defaultproperties +{ +} \ No newline at end of file