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