diff --git a/sources/Unreal/GameRules/AcediaGameRules.uc b/sources/Unreal/GameRules/AcediaGameRules.uc index 8552e9f..cc02d05 100644 --- a/sources/Unreal/GameRules/AcediaGameRules.uc +++ b/sources/Unreal/GameRules/AcediaGameRules.uc @@ -21,6 +21,9 @@ class AcediaGameRules extends GameRules; var private GameRules_OnFindPlayerStart_Signal onFindPlayerStartSignal; +var private GameRules_OnHandleRestartGame_Signal onHandleRestartGameSignal; +var private GameRules_OnCheckEndGame_Signal onCheckEndGameSignal; +var private GameRules_OnCheckScore_Signal onCheckScoreSignal; var private GameRules_OnOverridePickupQuery_Signal onOverridePickupQuery; var private GameRules_OnNetDamage_Signal onNetDamage; @@ -31,6 +34,12 @@ public final function Initialize(unrealService service) } onFindPlayerStartSignal = GameRules_OnFindPlayerStart_Signal( service.GetSignal(class'GameRules_OnFindPlayerStart_Signal')); + onHandleRestartGameSignal = GameRules_OnHandleRestartGame_Signal( + service.GetSignal(class'GameRules_OnHandleRestartGame_Signal')); + onCheckEndGameSignal = GameRules_OnCheckEndGame_Signal( + service.GetSignal(class'GameRules_OnCheckEndGame_Signal')); + onCheckScoreSignal = GameRules_OnCheckScore_Signal( + service.GetSignal(class'GameRules_OnCheckScore_Signal')); onOverridePickupQuery = GameRules_OnOverridePickupQuery_Signal( service.GetSignal(class'GameRules_OnOverridePickupQuery_Signal')); onNetDamage = GameRules_OnNetDamage_Signal( @@ -62,6 +71,43 @@ function NavigationPoint FindPlayerStart( return result; } +function bool HandleRestartGame() +{ + local bool result; + if (onHandleRestartGameSignal != none) { + result = onHandleRestartGameSignal.Emit(); + } + if (nextGameRules != none && nextGameRules.HandleRestartGame()) { + return true; + } + return result; +} + +function bool CheckEndGame(PlayerReplicationInfo winner, string reason) +{ + local bool result; + result = true; + if (onCheckEndGameSignal != none) { + result = onCheckEndGameSignal.Emit(winner, reason); + } + if (nextGameRules != none && !nextGameRules.HandleRestartGame()) { + return false; + } + return result; +} + +function bool CheckScore(PlayerReplicationInfo scorer) +{ + local bool result; + if (onCheckScoreSignal != none) { + result = onCheckScoreSignal.Emit(scorer); + } + if (nextGameRules != none && nextGameRules.CheckScore(Scorer)) { + return true; + } + return result; +} + function bool OverridePickupQuery( Pawn other, Pickup item, diff --git a/sources/Unreal/GameRules/Events/GameRules_OnCheckEndGame_Signal.uc b/sources/Unreal/GameRules/Events/GameRules_OnCheckEndGame_Signal.uc new file mode 100644 index 0000000..59a9cd3 --- /dev/null +++ b/sources/Unreal/GameRules/Events/GameRules_OnCheckEndGame_Signal.uc @@ -0,0 +1,47 @@ +/** + * Signal class implementation for `GameRulesAPI`'s `OnCheckEndGame` signal. + * 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 GameRules_OnCheckEndGame_Signal extends Signal; + +public final function bool Emit( + PlayerReplicationInfo winner, + string reason) +{ + local Slot nextSlot; + local bool result, nextReply; + StartIterating(); + nextSlot = GetNextSlot(); + result = true; + while (nextSlot != none) + { + nextReply = GameRules_OnCheckEndGame_Slot(nextSlot) + .connect(winner, reason); + if (!nextReply && !nextSlot.IsEmpty()) { + result = result && nextReply; + } + nextSlot = GetNextSlot(); + } + CleanEmptySlots(); + return result; +} + +defaultproperties +{ + relatedSlotClass = class'GameRules_OnCheckEndGame_Slot' +} \ No newline at end of file diff --git a/sources/Unreal/GameRules/Events/GameRules_OnCheckEndGame_Slot.uc b/sources/Unreal/GameRules/Events/GameRules_OnCheckEndGame_Slot.uc new file mode 100644 index 0000000..7395e4f --- /dev/null +++ b/sources/Unreal/GameRules/Events/GameRules_OnCheckEndGame_Slot.uc @@ -0,0 +1,41 @@ +/** + * Slot class implementation for `GameRulesAPI`'s `OnCheckEndGame` signal. + * 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 GameRules_OnCheckEndGame_Slot extends Slot; + +delegate bool connect(PlayerReplicationInfo winner, string reason) +{ + DummyCall(); + return true; +} + +protected function Constructor() +{ + connect = none; +} + +protected function Finalizer() +{ + super.Finalizer(); + connect = none; +} + +defaultproperties +{ +} \ No newline at end of file diff --git a/sources/Unreal/GameRules/Events/GameRules_OnCheckScore_Signal.uc b/sources/Unreal/GameRules/Events/GameRules_OnCheckScore_Signal.uc new file mode 100644 index 0000000..012612f --- /dev/null +++ b/sources/Unreal/GameRules/Events/GameRules_OnCheckScore_Signal.uc @@ -0,0 +1,44 @@ +/** + * Signal class implementation for `GameRulesAPI`'s `OnCheckScore` signal. + * 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 GameRules_OnCheckScore_Signal extends Signal; + +public final function bool Emit(PlayerReplicationInfo scorer) +{ + local Slot nextSlot; + local bool result, nextReply; + StartIterating(); + nextSlot = GetNextSlot(); + result = true; + while (nextSlot != none) + { + nextReply = GameRules_OnCheckScore_Slot(nextSlot).connect(scorer); + if (!nextReply && !nextSlot.IsEmpty()) { + result = result && nextReply; + } + nextSlot = GetNextSlot(); + } + CleanEmptySlots(); + return result; +} + +defaultproperties +{ + relatedSlotClass = class'GameRules_OnCheckScore_Slot' +} \ No newline at end of file diff --git a/sources/Unreal/GameRules/Events/GameRules_OnCheckScore_Slot.uc b/sources/Unreal/GameRules/Events/GameRules_OnCheckScore_Slot.uc new file mode 100644 index 0000000..e931aec --- /dev/null +++ b/sources/Unreal/GameRules/Events/GameRules_OnCheckScore_Slot.uc @@ -0,0 +1,41 @@ +/** + * Slot class implementation for `GameRulesAPI`'s `OnCheckScore` signal. + * 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 GameRules_OnCheckScore_Slot extends Slot; + +delegate bool connect(PlayerReplicationInfo scorer) +{ + DummyCall(); + return true; +} + +protected function Constructor() +{ + connect = none; +} + +protected function Finalizer() +{ + super.Finalizer(); + connect = none; +} + +defaultproperties +{ +} \ No newline at end of file diff --git a/sources/Unreal/GameRules/Events/GameRules_OnFindPlayerStart_Signal.uc b/sources/Unreal/GameRules/Events/GameRules_OnFindPlayerStart_Signal.uc index 61cba42..6978309 100644 --- a/sources/Unreal/GameRules/Events/GameRules_OnFindPlayerStart_Signal.uc +++ b/sources/Unreal/GameRules/Events/GameRules_OnFindPlayerStart_Signal.uc @@ -22,8 +22,7 @@ class GameRules_OnFindPlayerStart_Signal extends Signal; public final function NavigationPoint Emit( Controller player, optional byte inTeam, - optional string incomingName -) + optional string incomingName) { local Slot nextSlot; local NavigationPoint nextPoint; @@ -33,7 +32,9 @@ public final function NavigationPoint Emit( { nextPoint = GameRules_OnFindPlayerStart_Slot(nextSlot) .connect(player, inTeam, incomingName); - if (nextPoint != none && !nextSlot.IsEmpty()) { + if (nextPoint != none && !nextSlot.IsEmpty()) + { + CleanEmptySlots(); return nextPoint; } nextSlot = GetNextSlot(); diff --git a/sources/Unreal/GameRules/Events/GameRules_OnHandleRestartGame_Signal.uc b/sources/Unreal/GameRules/Events/GameRules_OnHandleRestartGame_Signal.uc new file mode 100644 index 0000000..e5b9ea2 --- /dev/null +++ b/sources/Unreal/GameRules/Events/GameRules_OnHandleRestartGame_Signal.uc @@ -0,0 +1,44 @@ +/** + * Signal class implementation for `GameRulesAPI`'s + * `OnHandleRestartGame` signal. + * 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 GameRules_OnHandleRestartGame_Signal extends Signal; + +public final function bool Emit() +{ + local Slot nextSlot; + local bool doPrevent, nextResult; + StartIterating(); + nextSlot = GetNextSlot(); + while (nextSlot != none) + { + nextResult = GameRules_OnHandleRestartGame_Slot(nextSlot).connect(); + if (nextResult && !nextSlot.IsEmpty()) { + doPrevent = doPrevent || nextResult; + } + nextSlot = GetNextSlot(); + } + CleanEmptySlots(); + return doPrevent; +} + +defaultproperties +{ + relatedSlotClass = class'GameRules_OnHandleRestartGame_Slot' +} \ No newline at end of file diff --git a/sources/Unreal/GameRules/Events/GameRules_OnHandleRestartGame_Slot.uc b/sources/Unreal/GameRules/Events/GameRules_OnHandleRestartGame_Slot.uc new file mode 100644 index 0000000..2386429 --- /dev/null +++ b/sources/Unreal/GameRules/Events/GameRules_OnHandleRestartGame_Slot.uc @@ -0,0 +1,41 @@ +/** + * Slot class implementation for `GameRulesAPI`'s `OnHandleRestartGame` signal. + * 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 GameRules_OnHandleRestartGame_Slot extends Slot; + +delegate bool connect() +{ + DummyCall(); + return false; +} + +protected function Constructor() +{ + connect = none; +} + +protected function Finalizer() +{ + super.Finalizer(); + connect = none; +} + +defaultproperties +{ +} \ No newline at end of file diff --git a/sources/Unreal/GameRules/Events/GameRules_OnOverridePickupQuery_Signal.uc b/sources/Unreal/GameRules/Events/GameRules_OnOverridePickupQuery_Signal.uc index ff54155..c52a00e 100644 --- a/sources/Unreal/GameRules/Events/GameRules_OnOverridePickupQuery_Signal.uc +++ b/sources/Unreal/GameRules/Events/GameRules_OnOverridePickupQuery_Signal.uc @@ -30,7 +30,9 @@ public final function bool Emit(Pawn other, Pickup item, out byte allowPickup) { shouldOverride = GameRules_OnOverridePickupQuery_Slot(nextSlot) .connect(other, item, allowPickup); - if (shouldOverride && !nextSlot.IsEmpty()) { + if (shouldOverride && !nextSlot.IsEmpty()) + { + CleanEmptySlots(); return shouldOverride; } nextSlot = GetNextSlot(); diff --git a/sources/Unreal/GameRules/GameRulesAPI.uc b/sources/Unreal/GameRules/GameRulesAPI.uc index 6b19cfb..a97013e 100644 --- a/sources/Unreal/GameRules/GameRulesAPI.uc +++ b/sources/Unreal/GameRules/GameRulesAPI.uc @@ -20,8 +20,6 @@ */ 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 @@ -46,15 +44,84 @@ public final function GameRules_OnFindPlayerStart_Slot OnFindPlayerStart( 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)); } +/** + * Called in `GameInfo`'s `RestartGame()` method and allows to prevent + * game's restart. + * + * This signal will always be propagated to all registered slots. + * + * [Signature] + * bool () + * + * @return `true` if you want to prevent game restart and `false` otherwise. + */ +/* SIGNAL */ +public final function GameRules_OnHandleRestartGame_Slot OnHandleRestartGame( + AcediaObject receiver) +{ + local Signal signal; + local UnrealService service; + service = UnrealService(class'UnrealService'.static.Require()); + signal = service.GetSignal(class'GameRules_OnHandleRestartGame_Signal'); + return GameRules_OnHandleRestartGame_Slot(signal.NewSlot(receiver)); +} + +/** + * Allows modification of game ending conditions. + * Return `false` to prevent game from ending. + * + * This signal will always be propagated to all registered slots. + * + * [Signature] + * bool (PlayerReplicationInfo winner, string reason) + * + * @param winner Replication info of the supposed winner of the game. + * @param reason String with a description about how/why `winner` has won. + * @return `false` if you want to prevent game from ending + * and `false` otherwise. + */ +/* SIGNAL */ +public final function GameRules_OnCheckEndGame_Slot OnCheckEndGame( + AcediaObject receiver) +{ + local Signal signal; + local UnrealService service; + service = UnrealService(class'UnrealService'.static.Require()); + signal = service.GetSignal(class'GameRules_OnHandleRestartGame_Signal'); + return GameRules_OnCheckEndGame_Slot(signal.NewSlot(receiver)); +} + +/* CheckScore() + +*/ +/** + * Check if this score means the game ends. + * + * Return `true` to override `GameInfo`'s `CheckScore()`, or if game was ended + * (with a call to `Level.Game.EndGame()`). + * + * [Signature] + * bool (PlayerReplicationInfo scorer) + * + * @param scorer For whom to do a score check. + * @return `true` to override `GameInfo`'s `CheckScore()`, or if game was ended + * and `false` otherwise. + */ +/* SIGNAL */ +public final function GameRules_OnCheckScore_Slot OnCheckScore( + AcediaObject receiver) +{ + local Signal signal; + local UnrealService service; + service = UnrealService(class'UnrealService'.static.Require()); + signal = service.GetSignal(class'GameRules_OnCheckScore_Signal'); + return GameRules_OnCheckScore_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 @@ -82,16 +149,10 @@ public final function GameRules_OnOverridePickupQuery_Slot 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 @@ -119,11 +180,6 @@ public final function GameRules_OnNetDamage_Slot OnNetDamage( 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)); } @@ -228,5 +284,4 @@ public final function bool AreAdded( defaultproperties { - errNoService = (l=LOG_Error,m="`UnrealService` could not be reached.") } \ No newline at end of file diff --git a/sources/Unreal/UnrealService.uc b/sources/Unreal/UnrealService.uc index f57bcb0..10cdc57 100644 --- a/sources/Unreal/UnrealService.uc +++ b/sources/Unreal/UnrealService.uc @@ -87,6 +87,9 @@ public event Tick(float delta) defaultproperties { serviceSignals(0) = (signalClass=class'GameRules_OnFindPlayerStart_Signal') - serviceSignals(1) = (signalClass=class'GameRules_OnOverridePickupQuery_Signal') - serviceSignals(2) = (signalClass=class'GameRules_OnNetDamage_Signal') + serviceSignals(1) = (signalClass=class'GameRules_OnHandleRestartGame_Signal') + serviceSignals(2) = (signalClass=class'GameRules_OnCheckEndGame_Signal') + serviceSignals(3) = (signalClass=class'GameRules_OnCheckScore_Signal') + serviceSignals(4) = (signalClass=class'GameRules_OnOverridePickupQuery_Signal') + serviceSignals(5) = (signalClass=class'GameRules_OnNetDamage_Signal') } \ No newline at end of file