Anton Tarasenko
4 years ago
11 changed files with 1064 additions and 0 deletions
@ -0,0 +1,26 @@
|
||||
/** |
||||
* Base class for all backends. Does not define anything meaningful, which |
||||
* also means it does not put any limitations on it's implementation. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class BaseBackend extends AcediaObject |
||||
abstract; |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,26 @@
|
||||
/** |
||||
* Base class for all frontends. Does not define anything meaningful, which |
||||
* also means it does not put any limitations on it's implementation. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class BaseFrontend extends AcediaObject |
||||
abstract; |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,41 @@
|
||||
/** |
||||
* Frontend skeleton for basic killing floor game mode. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class KFFrontend extends BaseBackend |
||||
abstract; |
||||
|
||||
var private config class<ATradingComponent> tradingClass; |
||||
var public ATradingComponent trading; |
||||
|
||||
protected function Constructor() |
||||
{ |
||||
if (tradingClass != none) { |
||||
trading = ATradingComponent(_.memory.Allocate(tradingClass)); |
||||
} |
||||
} |
||||
|
||||
protected function Finalizer() |
||||
{ |
||||
_.memory.Free(trading); |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
tradingClass = none |
||||
} |
@ -0,0 +1,196 @@
|
||||
/** |
||||
* Class, objects of which are expected to represent traders located on |
||||
* the map. In classic KF game mode it would represent areas behind closed |
||||
* doors that open during trader time and allow to purchase weapons and ammo. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class ATrader extends AcediaObject |
||||
abstract; |
||||
|
||||
/** |
||||
* Returns location of the trader. |
||||
* |
||||
* Trader is usually associated with an area where players can trade and |
||||
* not just one point. Value returned by this method is merely expected to |
||||
* return position that "makes sense" for the trader. |
||||
* It can be used to calculate distance and/or path to the trader. |
||||
* |
||||
* @return Location of the caller trader. |
||||
*/ |
||||
public function Vector GetLocation(); |
||||
|
||||
/** |
||||
* Returns name of the trader. |
||||
* |
||||
* Trader name can be any non-empty `Text`. |
||||
* The only requirement is that after map's initialization every trader |
||||
* should have a unique name. It is not forbidden to break this invariant later |
||||
* by `SetName()` method. |
||||
* If `none` or empty name is passed, this method should do nothing. |
||||
* |
||||
* This is not the hard requirement, but explanation of purpose. |
||||
* Name does not have to be player-friendly, but it must be human-readable: |
||||
* it is not expected to be seen by regular players, but admins might use it |
||||
* to tweak their server. |
||||
* |
||||
* @return Current name of the trader. |
||||
*/ |
||||
public function Text GetName(); |
||||
|
||||
/** |
||||
* Changes name of the trader. |
||||
* |
||||
* @see `GetName()` for more details. |
||||
* |
||||
* @param newName New name of the caller trader. |
||||
* @return `true` if trader is currently enabled and `false` otherwise. |
||||
*/ |
||||
public function ATrader SetName(Text newName); |
||||
|
||||
/** |
||||
* Checks if caller trader is currently enabled. |
||||
* |
||||
* Trader being enabled means that it can be opened and used for trading. |
||||
* Trader being disabled means that it cannot open for trading. |
||||
* |
||||
* This should override opened and auto-opened status. |
||||
* |
||||
* Marking disabled trader as selected is discouraged, especially for classic |
||||
* KF game mode, but should be allowed. |
||||
* |
||||
* @return `true` if trader is currently enabled and `false` otherwise. |
||||
*/ |
||||
public function bool IsEnabled(); |
||||
|
||||
/** |
||||
* Sets whether caller `ATrader`'s is currently enabled. |
||||
* |
||||
* Disabling the trader should automatically "boot" players out |
||||
* (see `BootPlayers()`). |
||||
* |
||||
* @see `IsEnabled()` for more info. |
||||
* |
||||
* @param doEnable `true` if trader is currently enabled and |
||||
* `false` otherwise. |
||||
* @return Caller `ATrader` to allow for method chaining. |
||||
*/ |
||||
public function ATrader SetEnabled(bool doEnable); |
||||
|
||||
/** |
||||
* Checks whether caller `ATrader` will auto-open when trading gets activated. |
||||
* |
||||
* This setting must be ignored if trader is disabled, but disabling `ATrader` |
||||
* should not reset it. |
||||
* |
||||
* @return `true` if trader is marked to always auto-open upon activating |
||||
* trading (unless it is also disabled) and `false` otherwise. |
||||
*/ |
||||
public function bool IsAutoOpen(); |
||||
|
||||
/** |
||||
* Checks whether caller `ATrader` will auto-open when trading gets activated. |
||||
* |
||||
* @see `IsAutoOpen()` for more info. |
||||
* |
||||
* @param doAutoOpen `true` if trader should be marked to always auto-open |
||||
* upon activating trading and `false` otherwise. |
||||
* @return Caller `ATrader` to allow for method chaining. |
||||
*/ |
||||
public function ATrader SetAutoOpen(bool doAutoOpen); |
||||
|
||||
/** |
||||
* Checks whether caller `ATrader` is currently open. |
||||
* |
||||
* `ATrader` being open means that players can "enter" (whatever that means for |
||||
* an implementation) and use `ATrader` to buy/sell equipment. |
||||
* |
||||
* @return `true` if it is open and `false` otherwise. |
||||
*/ |
||||
public function bool IsOpen(); |
||||
|
||||
/** |
||||
* Changes whether caller `ATrader` is open. |
||||
* |
||||
* Closing the trader should not automatically "boot" players out |
||||
* (see `BootPlayers()`). |
||||
* |
||||
* @see `IsOpen()` for more details. |
||||
* |
||||
* @param doOpen `true` if it is open and `false` otherwise. |
||||
* @return Caller `ATrader` to allow for method chaining. |
||||
*/ |
||||
public function ATrader SetOpen(bool doOpen); |
||||
|
||||
/** |
||||
* Checks whether caller `ATrader` is currently marked as selected. |
||||
* |
||||
* @see `ATradingComponent.GetSelectedTrader()` for more details. |
||||
* |
||||
* @return `true` if caller `ATrader` is selected and `false` otherwise. |
||||
*/ |
||||
public function bool IsSelected(); |
||||
|
||||
/** |
||||
* Marks caller `ATrader` as a selected trader. |
||||
* |
||||
* @see `ATradingComponent.GetSelectedTrader()` for more details. |
||||
* |
||||
* @return Caller `ATrader` to allow for method chaining. |
||||
*/ |
||||
public function ATrader Select(); |
||||
|
||||
/** |
||||
* Removes players from the trader's place. |
||||
* |
||||
* In classic KF game mode it teleported them right outside the doors. |
||||
* |
||||
* This method's goal is to make sure players are not stuck in trader's place |
||||
* after it is closed. If that is impossible (for traders resembling |
||||
* KF2's one), then this method should do nothing. |
||||
* |
||||
* @return Caller `ATrader` to allow for method chaining. |
||||
*/ |
||||
public function ATrader BootPlayers(); |
||||
|
||||
/** |
||||
* Shortcut method to open the caller trader, guaranteed to be equivalent to |
||||
* `SetOpen(true)`. Provided for better interface. |
||||
* |
||||
* @return Caller `ATrader` to allow for method chaining. |
||||
*/ |
||||
public final function ATrader Open() |
||||
{ |
||||
SetOpen(true); |
||||
return self; |
||||
} |
||||
|
||||
/** |
||||
* Shortcut method to close the caller trader, guaranteed to be equivalent to |
||||
* `SetOpen(false)`. Provided for better interface. |
||||
* |
||||
* @return Caller `ATrader` to allow for method chaining. |
||||
*/ |
||||
public final function ATrader Close() |
||||
{ |
||||
SetOpen(false); |
||||
return self; |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,204 @@
|
||||
/** |
||||
* Subset of functionality for dealing with everything related to traders. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class ATradingComponent extends AcediaObject |
||||
abstract; |
||||
|
||||
var protected SimpleSignal onStartSignal; |
||||
var protected SimpleSignal onEndSignal; |
||||
var protected Trading_OnSelect_Signal onTraderSelectSignal; |
||||
|
||||
protected function Constructor() |
||||
{ |
||||
onStartSignal = SimpleSignal(_.memory.Allocate(class'SimpleSignal')); |
||||
onEndSignal = SimpleSignal(_.memory.Allocate(class'SimpleSignal')); |
||||
onTraderSelectSignal = Trading_OnSelect_Signal( |
||||
_.memory.Allocate(class'Trading_OnSelect_Signal')); |
||||
} |
||||
|
||||
protected function Finalizer() |
||||
{ |
||||
_.memory.Free(onStartSignal); |
||||
_.memory.Free(onEndSignal); |
||||
_.memory.Free(onTraderSelectSignal); |
||||
} |
||||
|
||||
/** |
||||
* Signal that will be emitted whenever trading time starts. |
||||
* |
||||
* [Signature] |
||||
* void <slot>() |
||||
*/ |
||||
/* SIGNAL */ |
||||
public final function SimpleSlot OnStart(AcediaObject receiver) |
||||
{ |
||||
return SimpleSlot(onStartSignal.NewSlot(receiver)); |
||||
} |
||||
|
||||
/** |
||||
* Signal that will be emitted whenever trading time ends. |
||||
* |
||||
* [Signature] |
||||
* void <slot>(ATrader oldTrader, ATrader newTrader) |
||||
* |
||||
* @param oldTrader Trader that was selected before this event. |
||||
* @param newTrader Trader that will be selected after this event. |
||||
*/ |
||||
/* SIGNAL */ |
||||
public final function SimpleSlot OnEnd(AcediaObject receiver) |
||||
{ |
||||
return SimpleSlot(onEndSignal.NewSlot(receiver)); |
||||
} |
||||
|
||||
/** |
||||
* Signal that will be emitted whenever a new trader is selected. |
||||
* |
||||
* [Signature] |
||||
* void <slot>() |
||||
*/ |
||||
/* SIGNAL */ |
||||
public final function Trading_OnSelect_Slot OnTraderSelected( |
||||
AcediaObject receiver) |
||||
{ |
||||
return Trading_OnSelect_Slot(onTraderSelectSignal.NewSlot(receiver)); |
||||
} |
||||
|
||||
/** |
||||
* Returns array with all existing traders (including disabled once) on |
||||
* the level. |
||||
* |
||||
* @return Array of existing traders on the level. Guaranteed to not contain |
||||
* `none`-references. None of them should be deallocated, |
||||
* otherwise Acedia's behavior is undefined. |
||||
*/ |
||||
public function array<ATrader> GetTraders(); |
||||
|
||||
/** |
||||
* Checks whether trading is currently active. |
||||
* |
||||
* For classic KF game mode it means that it is trader time and one |
||||
* (or several) traders are open. |
||||
* This interface does not impose such limitation on trading: it is |
||||
* allowed to be active at any time, independent of anything else. However |
||||
* trading should only be permitted while trading is active. |
||||
* |
||||
* @return `true` if trading is active and `false` otherwise. |
||||
*/ |
||||
public function bool IsTradingActive(); |
||||
|
||||
/** |
||||
* Changes current status of trading. |
||||
* |
||||
* @see `IsTradingActive()` for more details. |
||||
*/ |
||||
public function SetTradingStatus(bool makeActive); |
||||
|
||||
/** |
||||
* Returns the amount of time (in seconds) trading period will last for. |
||||
* |
||||
* For classic KF game mode it refers to how long trader time is |
||||
* (`60` seconds by default). |
||||
* |
||||
* @return Amount of time (in seconds) trading period will last for. |
||||
*/ |
||||
public function int GetTradingInterval(); |
||||
|
||||
/** |
||||
* Changes the amount of time (in seconds) trading period will last for. |
||||
* |
||||
* Changing this setting only affect current round (until the end of the map). |
||||
* |
||||
* For classic KF game mode it refers to how long trader time is |
||||
* (`60` seconds by default). |
||||
* |
||||
* @param newTradingInterval New length of the trading period. |
||||
*/ |
||||
public function SetTradingInterval(int newTradingInterval); |
||||
|
||||
/** |
||||
* Return amount of time remaining in the current trading period. |
||||
* |
||||
* For classic KF game mode this refers to remaining trading time. |
||||
* |
||||
* @return Amount of time remaining in the current trading period. |
||||
* `0` if trading is currently inactive. |
||||
*/ |
||||
public function int GetCountdown(); |
||||
|
||||
/** |
||||
* Changes amount of time remaining in the current trading period. |
||||
* |
||||
* For classic KF game mode this refers to remaining trading time. |
||||
* |
||||
* @param newTradingInterval New amount of time that should remain in the |
||||
* current trading period. Values `<= 0` will lead to trading time ending |
||||
* immediately. |
||||
*/ |
||||
public function SetCountdown(int newTradingInterval); |
||||
|
||||
/** |
||||
* Checks whether trading countdown was paused. |
||||
* |
||||
* Pause only affects current trading period and will be reset after |
||||
* the next starts. |
||||
* |
||||
* @return `true` if trading countdown was paused and `false` otherwise. |
||||
* If trading is inactive - returns `false`. |
||||
*/ |
||||
public function bool IsCountDownPaused(); |
||||
|
||||
/** |
||||
* Changes whether trading countdown should be paused. |
||||
* |
||||
* Pause set by this method only affects current trading period and will be |
||||
* reset after the next starts. |
||||
* |
||||
* @return doPause `true` to pause trading countdown and `false` to resume. |
||||
* If trading time is currently inactive - does nothing. |
||||
*/ |
||||
public function SetCountDownPause(bool doPause); |
||||
|
||||
/** |
||||
* Returns currently selected trader. |
||||
* |
||||
* For classing KF game mode selected trader means the trader currently |
||||
* pointed at by the arrow in the top left corner on HUD and by the red wisp |
||||
* during trading time. |
||||
* This interface allows to generalize the concept of select trader to any |
||||
* specially marked trader or even not make use of it at all. |
||||
* Changing a selected trader in any way should always be followed |
||||
* by emitting `OnTraderSelected()` signal. |
||||
* After `SelectTrader()` call `GetSelectedTrader()` should return |
||||
* specified `ATrader`. If selected trader changes in some other way, it should |
||||
* first result in emitted `OnTraderSelected()` signal. |
||||
* |
||||
* @return Currently selected trader. |
||||
*/ |
||||
public function ATrader GetSelectedTrader(); |
||||
|
||||
/** |
||||
* Changes currently selected trader. |
||||
* |
||||
* @see `GetSelectedTrader()` for more details. |
||||
*/ |
||||
public function SelectTrader(ATrader newSelection); |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,39 @@
|
||||
/** |
||||
* Signal class implementation for `ATradingComponent`, for detecting when |
||||
* another trader is selected. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class Trading_OnSelect_Signal extends Signal; |
||||
|
||||
public final function Emit(ATrader oldTrader, ATrader newTrader) |
||||
{ |
||||
local Slot nextSlot; |
||||
StartIterating(); |
||||
nextSlot = GetNextSlot(); |
||||
while (nextSlot != none) |
||||
{ |
||||
Trading_OnSelect_Slot(nextSlot).connect(oldTrader, newTrader); |
||||
nextSlot = GetNextSlot(); |
||||
} |
||||
CleanEmptySlots(); |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
relatedSlotClass = class'Trading_OnSelect_Slot' |
||||
} |
@ -0,0 +1,41 @@
|
||||
/** |
||||
* Slot class implementation for `ATradingComponent`'s signal for |
||||
* detecting when another trader is selected. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class Trading_OnSelect_Slot extends Slot; |
||||
|
||||
delegate connect(ATrader oldTrader, ATrader newTrader) |
||||
{ |
||||
DummyCall(); |
||||
} |
||||
|
||||
protected function Constructor() |
||||
{ |
||||
connect = none; |
||||
} |
||||
|
||||
protected function Finalizer() |
||||
{ |
||||
super.Finalizer(); |
||||
connect = none; |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,27 @@
|
||||
/** |
||||
* Frontend implementation for classic `KFGameType` that changes as little as |
||||
* possible and only on request from another mod, otherwise not altering |
||||
* gameplay at all. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class KF1_Frontend extends KFFrontend; |
||||
|
||||
defaultproperties |
||||
{ |
||||
tradingClass = class'KF1_TradingComponent' |
||||
} |
@ -0,0 +1,248 @@
|
||||
/** |
||||
* `ATrader`'s implementation for `KF1_Frontend`. |
||||
* Wrapper for KF1's `ShopVolume`s. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class KF1_Trader extends ATrader; |
||||
|
||||
// We do not use any vanilla value as a name, instead storing and tracking it |
||||
// entirely as our own value. |
||||
var protected Text myName; |
||||
// Reference to `ShopVolume` actor that this `KF1_Trader` represents. |
||||
var protected NativeActorRef myShopVolume; |
||||
|
||||
protected function Finalizer() |
||||
{ |
||||
_.memory.Free(myShopVolume); |
||||
myShopVolume = none; |
||||
} |
||||
|
||||
/** |
||||
* Detect all existing traders on the level and created a `KF1_Trader` for |
||||
* each of them. |
||||
* |
||||
* @return Array of created `KF1_Trader`s. All of them are guaranteed to not |
||||
* be `none`. |
||||
*/ |
||||
public static function array<KF1_Trader> WrapVanillaShops() |
||||
{ |
||||
local int shopCounter; |
||||
local MutableText textBuilder; |
||||
local LevelInfo level; |
||||
local KFGameType kfGame; |
||||
local KF1_Trader nextTrader; |
||||
local array<KF1_Trader> allTraders; |
||||
local ShopVolume nextShopVolume; |
||||
level = __().unreal.GetLevel(); |
||||
kfGame = __().unreal.GetKFGameType(); |
||||
textBuilder = __().text.Empty(); |
||||
foreach level.AllActors(class'ShopVolume', nextShopVolume) |
||||
{ |
||||
if (nextShopVolume == none) continue; |
||||
if (!nextShopVolume.bObjectiveModeOnly || kfGame.bUsingObjectiveMode) |
||||
{ |
||||
nextTrader = KF1_Trader(__().memory.Allocate(class'KF1_Trader')); |
||||
nextTrader.myShopVolume = __().unreal.ActorRef(nextShopVolume); |
||||
textBuilder.Clear().AppendPlainString("trader" $ shopCounter); |
||||
nextTrader.myName = textBuilder.Copy(); |
||||
allTraders[allTraders.length] = nextTrader; |
||||
shopCounter += 1; |
||||
} |
||||
} |
||||
textBuilder.FreeSelf(); |
||||
return allTraders; |
||||
} |
||||
|
||||
public function Text GetName() |
||||
{ |
||||
if (myName == none) { |
||||
return _.text.Empty(); |
||||
} |
||||
return myName.Copy(); |
||||
} |
||||
|
||||
public function ATrader SetName(Text newName) |
||||
{ |
||||
if (newName == none) return self; |
||||
if (newName.IsEmpty()) return self; |
||||
|
||||
myName.FreeSelf(); |
||||
newName = newName.Copy(); |
||||
return self; |
||||
} |
||||
|
||||
public function Vector GetLocation() |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume != none) { |
||||
return vanillaShopVolume.location; |
||||
} |
||||
return Vect(0, 0, 0); |
||||
} |
||||
|
||||
public function bool IsEnabled() |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume != none) { |
||||
return !vanillaShopVolume.bAlwaysClosed; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public function ATrader SetEnabled(bool doEnable) |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume == none) { |
||||
return self; |
||||
} |
||||
if (doEnable) { |
||||
vanillaShopVolume.bAlwaysClosed = false; |
||||
} |
||||
else |
||||
{ |
||||
vanillaShopVolume.bAlwaysClosed = true; |
||||
Close(); |
||||
BootPlayers(); |
||||
} |
||||
UpdateShopList(); |
||||
return self; |
||||
} |
||||
|
||||
/** |
||||
* This method re-fills `KFGameType.shopList` to contain only currently |
||||
* enabled traders. |
||||
*/ |
||||
protected function UpdateShopList() |
||||
{ |
||||
local int i; |
||||
local ShopVolume nextShopVolume; |
||||
local KF1_Trader nextTrader; |
||||
local array<ShopVolume> shopVolumes; |
||||
local array<ATrader> availableTraders; |
||||
availableTraders = _.kf.trading.GetTraders(); |
||||
for (i = 0; i < availableTraders.length; i += 1) |
||||
{ |
||||
nextTrader = KF1_Trader(availableTraders[i]); |
||||
if (nextTrader == none) continue; |
||||
if (!nextTrader.IsEnabled()) continue; |
||||
nextShopVolume = ShopVolume(nextTrader.myShopVolume.Get()); |
||||
if (nextShopVolume == none) continue; |
||||
|
||||
shopVolumes[shopVolumes.length] = nextShopVolume; |
||||
} |
||||
_.unreal.GetKFGameType().shopList = shopVolumes; |
||||
} |
||||
|
||||
public function bool IsAutoOpen() |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume != none) { |
||||
return vanillaShopVolume.bAlwaysEnabled; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public function ATrader SetAutoOpen(bool doAutoOpen) |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume == none) { |
||||
return self; |
||||
} |
||||
if (doAutoOpen) { |
||||
vanillaShopVolume.bAlwaysEnabled = true; |
||||
} |
||||
else { |
||||
vanillaShopVolume.bAlwaysEnabled = false; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
public function bool IsOpen() |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume != none) { |
||||
return vanillaShopVolume.bCurrentlyOpen; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public function ATrader SetOpen(bool doOpen) |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
if (doOpen && !IsEnabled()) return self; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume == none) return self; |
||||
|
||||
if (doOpen) { |
||||
vanillaShopVolume.OpenShop(); |
||||
} |
||||
else { |
||||
vanillaShopVolume.CloseShop(); |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
public function bool IsSelected() |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
local KFGameReplicationInfo kfGameRI; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume == none) { |
||||
return false; |
||||
} |
||||
kfGameRI = _.unreal.GetKFGameRI(); |
||||
if (kfGameRI != none) { |
||||
return (kfGameRI.currentShop == vanillaShopVolume); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public function ATrader Select() |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
local KFGameReplicationInfo kfGameRI; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume == none) { |
||||
return self; |
||||
} |
||||
kfGameRI = _.unreal.GetKFGameRI(); |
||||
if (kfGameRI != none) { |
||||
kfGameRI.currentShop = vanillaShopVolume; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
public function ATrader BootPlayers() |
||||
{ |
||||
local ShopVolume vanillaShopVolume; |
||||
vanillaShopVolume = ShopVolume(myShopVolume.Get()); |
||||
if (vanillaShopVolume != none) { |
||||
vanillaShopVolume.BootPlayers(); |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,213 @@
|
||||
/** |
||||
* `ATradingComponent`'s implementation for `KF1_Frontend`. |
||||
* Only supports `KF1_Trader` as a possible trader class. |
||||
* Copyright 2021 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 <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class KF1_TradingComponent extends ATradingComponent; |
||||
|
||||
// Variables for enforcing a trader time pause by repeatedly setting |
||||
// `waveCountDown`'s value to `pausedCountDownValue` |
||||
var protected bool tradingCountDownPaused; |
||||
var protected int pausedCountDownValue; |
||||
|
||||
// For detecting events of trading becoming active/inactive and selecting |
||||
// a different trader, to account for these changing through non-Acedia means |
||||
var protected bool wasActiveLastCheck; |
||||
var protected Atrader lastSelectedTrader; |
||||
|
||||
// All known traders on map |
||||
var protected array<ATrader> registeredTraders; |
||||
|
||||
protected function Constructor() |
||||
{ |
||||
super.Constructor(); |
||||
_.unreal.OnTick(self).connect = Tick; |
||||
registeredTraders = class'KF1_Trader'.static.WrapVanillaShops(); |
||||
lastSelectedTrader = GetSelectedTrader(); |
||||
wasActiveLastCheck = IsTradingActive(); |
||||
} |
||||
|
||||
protected function Finalizer() |
||||
{ |
||||
super.Finalizer(); |
||||
_.unreal.OnTick(self).Disconnect(); |
||||
_.memory.FreeMany(registeredTraders); |
||||
registeredTraders.length = 0; |
||||
} |
||||
|
||||
public function array<ATrader> GetTraders() |
||||
{ |
||||
return registeredTraders; |
||||
} |
||||
|
||||
public function bool IsTradingActive() |
||||
{ |
||||
local KFGameType kfGame; |
||||
kfGame = _.unreal.GetKFGameType(); |
||||
return kfGame.IsInState('MatchInProgress') && kfGame.bTradingDoorsOpen; |
||||
} |
||||
|
||||
public function SetTradingStatus(bool makeActive) |
||||
{ |
||||
local bool isCurrentlyActive; |
||||
local KFGameType kfGame; |
||||
local KFGameReplicationInfo kfGameRI; |
||||
local KFMonster nextZed; |
||||
isCurrentlyActive = IsTradingActive(); |
||||
if (isCurrentlyActive == makeActive) { |
||||
return; |
||||
} |
||||
if (!makeActive && isCurrentlyActive) |
||||
{ |
||||
SetCountDown(0); |
||||
return; |
||||
} |
||||
kfGame = _.unreal.GetKFGameType(); |
||||
kfGameRI = _.unreal.GetKFGameRI(); |
||||
foreach kfGame.DynamicActors(class'KFMonster', nextZed) |
||||
{ |
||||
if (nextZed == none) continue; |
||||
if (nextZed.health <= 0) continue; |
||||
nextZed.Suicide(); |
||||
} |
||||
kfGame.totalMaxMonsters = 0; |
||||
kfGameRI.maxMonsters = 0; |
||||
} |
||||
|
||||
public function ATrader GetSelectedTrader() |
||||
{ |
||||
local int i; |
||||
for (i = 0; i < registeredTraders.length; i += 1) |
||||
{ |
||||
if (registeredTraders[i].IsSelected()) { |
||||
return registeredTraders[i]; |
||||
} |
||||
} |
||||
return none; |
||||
} |
||||
|
||||
public function SelectTrader(ATrader newSelection) |
||||
{ |
||||
local ATrader oldSelection; |
||||
local KFGameReplicationInfo kfGameRI; |
||||
if (newSelection != none) { |
||||
newSelection.Select(); |
||||
} |
||||
else |
||||
{ |
||||
kfGameRI = _.unreal.GetKFGameRI(); |
||||
if (kfGameRI != none) { |
||||
kfGameRI.currentShop = none; |
||||
} |
||||
} |
||||
// Emit signal, but first record new trader inside `lastSelectedTrader` |
||||
// in case someone decides it would be a grand idea to call `SelectTrader` |
||||
// during `onTraderSelectSignal` signal. |
||||
oldSelection = lastSelectedTrader; |
||||
lastSelectedTrader = newSelection; |
||||
if (lastSelectedTrader != newSelection) { |
||||
onTraderSelectSignal.Emit(oldSelection, newSelection); |
||||
} |
||||
} |
||||
|
||||
public function int GetTradingInterval() |
||||
{ |
||||
return _.unreal.GetKFGameType().timeBetweenWaves; |
||||
} |
||||
|
||||
public function SetTradingInterval(int newTradingInterval) |
||||
{ |
||||
if (newTradingInterval > 0) { |
||||
_.unreal.GetKFGameType().timeBetweenWaves = Max(newTradingInterval, 1); |
||||
} |
||||
} |
||||
|
||||
public function int GetCountDown() |
||||
{ |
||||
if (!IsTradingActive()) { |
||||
return 0; |
||||
} |
||||
return _.unreal.GetKFGameType().waveCountDown; |
||||
} |
||||
|
||||
public function SetCountDown(int newCountDownValue) |
||||
{ |
||||
local KFGameType kfGame; |
||||
if (!IsTradingActive()) { |
||||
return; |
||||
} |
||||
kfGame = _.unreal.GetKFGameType(); |
||||
if (kfGame.waveCountDown >= 5 && newCountDownValue < 5) { |
||||
_.unreal.GetKFGameRI().waveNumber = kfGame.waveNum; |
||||
} |
||||
kfGame.waveCountDown = Max(newCountDownValue, 1); |
||||
pausedCountDownValue = newCountDownValue; |
||||
} |
||||
|
||||
public function bool IsCountDownPaused() |
||||
{ |
||||
if (!IsTradingActive()) { |
||||
return false; |
||||
} |
||||
return tradingCountDownPaused; |
||||
} |
||||
|
||||
public function SetCountDownPause(bool doPause) |
||||
{ |
||||
tradingCountDownPaused = doPause; |
||||
if (doPause) { |
||||
pausedCountDownValue = _.unreal.GetKFGameType().waveCountDown; |
||||
} |
||||
} |
||||
|
||||
protected function Tick(float delta, float timeScaleCoefficient) |
||||
{ |
||||
local bool isActiveNow; |
||||
local ATrader newSelectedTrader; |
||||
// Enforce pause |
||||
if (tradingCountDownPaused) { |
||||
_.unreal.GetKFGameType().waveCountDown = pausedCountDownValue; |
||||
} |
||||
// Selected trader check |
||||
newSelectedTrader = GetSelectedTrader(); |
||||
if (lastSelectedTrader != newSelectedTrader) |
||||
{ |
||||
onTraderSelectSignal.Emit(lastSelectedTrader, newSelectedTrader); |
||||
lastSelectedTrader = newSelectedTrader; |
||||
} |
||||
// Active status check |
||||
isActiveNow = IsTradingActive(); |
||||
if (wasActiveLastCheck != isActiveNow) |
||||
{ |
||||
wasActiveLastCheck = isActiveNow; |
||||
if (isActiveNow) |
||||
{ |
||||
onStartSignal.Emit(); |
||||
} |
||||
else |
||||
{ |
||||
onEndSignal.Emit(); |
||||
// Reset pause after trading time has ended |
||||
tradingCountDownPaused = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
Loading…
Reference in new issue