/**
* Low-level API that provides set of utility methods for working with
* `GameRule`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 .
*/
class GameRulesAPI extends AcediaObject;
var private LoggerAPI.Definition errNoService;
/**
* Called when game decides on a player's spawn point. If a `NavigationPoint`
* is returned, signal propagation will be interrupted and returned value will
* be used as the player start.
*
* [Signature]
* NavigationPoint (
* Controller player,
* optional byte inTeam,
* optional string incomingName)
*
* @param player Player for whom we are picking a spawn point.
* @param inTeam Player's team number.
* @param incomingName `Portal` parameter from `GameInfo.Login()` event.
* @return `NavigationPoint` that will player must be spawned at.
* `none` means that slot does not want to modify it.
*/
/* SIGNAL */
public final function GameRules_OnFindPlayerStart_Slot OnFindPlayerStart(
AcediaObject receiver)
{
local Signal signal;
local UnrealService service;
service = UnrealService(class'UnrealService'.static.Require());
if (service == none)
{
_.logger.Auto(errNoService);
return none;
}
signal = service.GetSignal(class'GameRules_OnFindPlayerStart_Signal');
return GameRules_OnFindPlayerStart_Slot(signal.NewSlot(receiver));
}
/**
* When pawn wants to pickup something, `GameRule`s are given a chance to
* modify it. If one of the `Slot`s returns `true`, `allowPickup` will
* determine if the object can be picked up.
* Overriding via this method allows to completely bypass check against
* `Pawn`'s inventory's `HandlePickupQuery()` method.
*
* [Signature]
* bool (Pawn other, Pickup item, out byte allowPickup)
*
* @param other Pawn which will potentially pickup `item`.
* @param item Pickup which `other` might potentially pickup.
* @param allowPickup `true` if you want to force `other` to pickup an item
* and `false` otherwise. This parameter is ignored if returned value of
* your slot call is `false`.
* @return `true` if you wish to override decision about pickup with
* `allowPickup` and `false` if you do not want to make that decision.
* If you do decide to override decision by returning `true` - this signal
* will not be propagated to the rest of the slots.
*/
/* SIGNAL */
public final function GameRules_OnOverridePickupQuery_Slot
OnOverridePickupQuery(AcediaObject receiver)
{
local Signal signal;
local UnrealService service;
service = UnrealService(class'UnrealService'.static.Require());
if (service == none)
{
_.logger.Auto(errNoService);
return none;
}
signal = service.GetSignal(class'GameRules_OnOverridePickupQuery_Signal');
return GameRules_OnOverridePickupQuery_Slot(signal.NewSlot(receiver));
}
// TODO: rewrite
/**
* When pawn wants to pickup something, `GameRule`s are given a chance to
* modify it. If one of the `Slot`s returns `true`, `allowPickup` will
* determine if the object can be picked up.
* Overriding via this method allows to completely bypass check against
* `Pawn`'s inventory's `HandlePickupQuery()` method.
*
* [Signature]
* bool (Pawn other, Pickup item, out byte allowPickup)
*
* @param other Pawn which will potentially pickup `item`.
* @param item Pickup which `other` might potentially pickup.
* @param allowPickup `true` if you want to force `other` to pickup an item
* and `false` otherwise. This parameter is ignored if returned value of
* your slot call is `false`.
* @return `true` if you wish to override decision about pickup with
* `allowPickup` and `false` if you do not want to make that decision.
* If you do decide to override decision by returning `true` - this signal
* will not be propagated to the rest of the slots.
*/
/* SIGNAL */
public final function GameRules_OnNetDamage_Slot OnNetDamage(
AcediaObject receiver)
{
local Signal signal;
local UnrealService service;
service = UnrealService(class'UnrealService'.static.Require());
if (service == none)
{
_.logger.Auto(errNoService);
return none;
}
signal = service.GetSignal(class'GameRules_OnNetDamage_Signal');
return GameRules_OnNetDamage_Slot(signal.NewSlot(receiver));
}
/**
* Adds new `GameRules` class to the current `GameInfo`.
* Does nothing if give `GameRules` class was already added before.
*
* @param newRulesClass Class of rules to add.
* @return `true` if `GameRules` were added and `false` otherwise
* (because they were already active.)
*/
public final function bool Add(class newRulesClass)
{
if (AreAdded(newRulesClass)) {
return false;
}
_.unreal.GetGameType()
.AddGameModifier(GameRules(_.memory.Allocate(newRulesClass)));
return true;
}
/**
* Removes given `GameRules` class from the current `GameInfo`,
* if they are active. Does nothing otherwise.
*
* @param rulesClassToRemove Class of rules to try and remove.
* @return `true` if `GameRules` were removed and `false` otherwise
* (if they were not active in the first place).
*/
public final function bool Remove(class rulesClassToRemove)
{
local GameInfo game;
local GameRules rulesIter;
local GameRules rulesToDestroy;
if (rulesClassToRemove == none) return false;
game = _.unreal.GetGameType();
if (game.gameRulesModifiers == none) return false;
// Check root rules
rulesToDestroy = game.gameRulesModifiers;
if (rulesToDestroy.class == rulesClassToRemove)
{
game.gameRulesModifiers = rulesToDestroy.nextGameRules;
rulesToDestroy.Destroy();
return true;
}
// Check rest of the rules
rulesIter = game.gameRulesModifiers;
while (rulesIter != none)
{
rulesToDestroy = rulesIter.nextGameRules;
if ( rulesToDestroy != none
&& rulesToDestroy.class == rulesClassToRemove)
{
rulesIter.nextGameRules = rulesToDestroy.nextGameRules;
rulesToDestroy.Destroy();
return true;
}
rulesIter = rulesIter.nextGameRules;
}
return false;
}
/**
* Finds given class of `GameRules` if it's currently active in `GameInfo`.
* Returns `none` otherwise.
*
* @param rulesClassToFind Class of rules to find.
* @return `GameRules` of given class `rulesClassToFind` instance added to
* `GameInfo`'s records and `none` if no such rules are currently added.
*/
public final function GameRules FindInstance(
class rulesClassToFind)
{
local GameRules rulesIter;
if (rulesClassToFind == none) {
return none;
}
rulesIter = _.unreal.GetGameType().gameRulesModifiers;
while (rulesIter != none)
{
if (rulesIter.class == rulesClassToFind) {
return rulesIter;
}
rulesIter = rulesIter.nextGameRules;
}
return none;
}
/**
* Checks if given class of `GameRules` is currently active in `GameInfo`.
*
* @param rulesClassToCheck Class of rules to check for.
* @return `true` if `GameRules` are active and `false` otherwise.
*/
public final function bool AreAdded(
class rulesClassToCheck)
{
return (FindInstance(rulesClassToCheck) != none);
}
defaultproperties
{
errNoService = (l=LOG_Error,m="`UnrealService` could not be reached.")
}