Anton Tarasenko
2 years ago
3 changed files with 431 additions and 0 deletions
@ -0,0 +1,205 @@ |
|||||||
|
/** |
||||||
|
* Command for making player immortal. |
||||||
|
* Copyright 2022 Anton Tarasenko |
||||||
|
*------------------------------------------------------------------------------ |
||||||
|
* This file is part of Acedia. |
||||||
|
* |
||||||
|
* Acedia is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation, version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* Acedia is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
class ACommandGod extends Command; |
||||||
|
|
||||||
|
struct GodStatus |
||||||
|
{ |
||||||
|
// Player to whom we grant godhood |
||||||
|
var EPlayer target; |
||||||
|
// Is `target` only a demigod (can get damaged, but not die)? |
||||||
|
var bool demigod; |
||||||
|
// Should `target` be unaffected by attacks momentum? |
||||||
|
var bool unmovable; |
||||||
|
}; |
||||||
|
|
||||||
|
var private array<GodStatus> godhoodList; |
||||||
|
|
||||||
|
var private ACommandGod_Announcer announcer; |
||||||
|
|
||||||
|
var private const int TDAMAGE, TMOMENTUM; |
||||||
|
|
||||||
|
protected function Finalizer() |
||||||
|
{ |
||||||
|
_.memory.Free(announcer); |
||||||
|
_.kf.health.OnDamage(self).Disconnect(); |
||||||
|
super.Finalizer(); |
||||||
|
} |
||||||
|
|
||||||
|
protected function BuildData(CommandDataBuilder builder) |
||||||
|
{ |
||||||
|
builder.Name(P("god")).Group(P("gameplay")) |
||||||
|
.Summary(P("Command for making player immortal.")); |
||||||
|
builder.RequireTarget() |
||||||
|
.Describe(P("Gives targeted players god status, making them" |
||||||
|
@ "invincible.")); |
||||||
|
builder.SubCommand(P("list")) |
||||||
|
.Describe(P("Reports godhood status of targeted players.")); |
||||||
|
builder.SubCommand(P("strip")) |
||||||
|
.Describe(P("Strips targeted players from the godhood status.")); |
||||||
|
builder.Option(P("demi")) |
||||||
|
.Describe(P("This flag makes targeted players \"demigods\" instead -" |
||||||
|
@ "they still cannot die, but they can take any non-lethal" |
||||||
|
@ "damage.")); |
||||||
|
builder.Option(P("unmovable")) |
||||||
|
.Describe(P("This flag also prevents targeted players from being" |
||||||
|
@ "affected by the momentum trasnferred from damaging attacks.")); |
||||||
|
announcer = ACommandGod_Announcer( |
||||||
|
_.memory.Allocate(class'ACommandGod_Announcer')); |
||||||
|
_.kf.health.OnDamage(self).connect = ProtectDivines; |
||||||
|
} |
||||||
|
|
||||||
|
protected function ExecutedFor( |
||||||
|
EPlayer target, |
||||||
|
CallData arguments, |
||||||
|
EPlayer instigator) |
||||||
|
{ |
||||||
|
local GodStatus newGodStatus; |
||||||
|
|
||||||
|
announcer.Setup(target, instigator, othersConsole); |
||||||
|
if (arguments.subCommandName.IsEmpty()) |
||||||
|
{ |
||||||
|
newGodStatus.target = target; |
||||||
|
newGodStatus.demigod = arguments.options.HasKey(P("demi")); |
||||||
|
newGodStatus.unmovable = arguments.options.HasKey(P("unmovable")); |
||||||
|
MakeGod(target, newGodStatus); |
||||||
|
} |
||||||
|
else if (arguments.subCommandName.Compare(P("list"))) { |
||||||
|
announcer.AnnounceGodStatus(BorrowGodStatus(target)); |
||||||
|
} |
||||||
|
else if (arguments.subCommandName.Compare(P("strip"))) { |
||||||
|
RemoveGod(target); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private function ProtectDivines( |
||||||
|
EPawn target, |
||||||
|
EPawn instigator, |
||||||
|
HashTable damageData) |
||||||
|
{ |
||||||
|
local int damage; |
||||||
|
local EPlayer targetedPlayer; |
||||||
|
local GodStatus targetDivinity; |
||||||
|
|
||||||
|
targetedPlayer = target.GetPlayer(); |
||||||
|
targetDivinity = BorrowGodStatus(targetedPlayer); |
||||||
|
_.memory.Free(targetedPlayer); |
||||||
|
if (targetDivinity.target == none) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if (targetDivinity.unmovable) { |
||||||
|
damageData.SetVector(T(TMOMENTUM), Vect(0.0f, 0.0f, 0.0f)); |
||||||
|
} |
||||||
|
if (targetDivinity.demiGod) |
||||||
|
{ |
||||||
|
damage = damageData.GetInt(T(TDAMAGE)); |
||||||
|
damage = Min(damage, target.GetHealth() - 1); |
||||||
|
damageData.SetInt(T(TDAMAGE), damage); |
||||||
|
} |
||||||
|
else { |
||||||
|
damageData.SetInt(T(TDAMAGE), 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private final function MakeGod( |
||||||
|
EPlayer target, |
||||||
|
GodStatus newGodStatus) |
||||||
|
{ |
||||||
|
local int godIndex; |
||||||
|
local bool wasGod; |
||||||
|
local GodStatus oldGodStatus; |
||||||
|
|
||||||
|
if (target == none) { |
||||||
|
return; |
||||||
|
} |
||||||
|
for (godIndex = 0; godIndex < godhoodList.length; godIndex += 1) |
||||||
|
{ |
||||||
|
if (target.SameAs(godhoodList[godIndex].target)) |
||||||
|
{ |
||||||
|
wasGod = true; |
||||||
|
oldGodStatus = godhoodList[godIndex]; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
if (wasGod) |
||||||
|
{ |
||||||
|
if ( newGodStatus.demiGod == oldGodStatus.demiGod |
||||||
|
&& newGodStatus.unmovable == oldGodStatus.unmovable) |
||||||
|
{ |
||||||
|
announcer.AnnounceSameGod(newGodStatus); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
announcer.AnnounceChangedGod(oldGodStatus, newGodStatus); |
||||||
|
godhoodList[godIndex].target.FreeSelf(); |
||||||
|
newGodStatus.target.NewRef(); |
||||||
|
godhoodList[godIndex] = newGodStatus; |
||||||
|
} |
||||||
|
} |
||||||
|
else { |
||||||
|
announcer.AnnounceNewGod(newGodStatus); |
||||||
|
newGodStatus.target.NewRef(); |
||||||
|
godhoodList[godhoodList.length] = newGodStatus; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private final function RemoveGod(EPlayer target) |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
|
||||||
|
if (target == none) { |
||||||
|
return; |
||||||
|
} |
||||||
|
for (i = 0; i < godhoodList.length; i += 1) |
||||||
|
{ |
||||||
|
if (target.SameAs(godhoodList[i].target)) |
||||||
|
{ |
||||||
|
announcer.AnnounceRemoveGod(godhoodList[i]); |
||||||
|
godhoodList[i].target.FreeSelf(); |
||||||
|
godhoodList.Remove(i, 1); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
announcer.AnnounceWasNotGod(); |
||||||
|
} |
||||||
|
|
||||||
|
private final function GodStatus BorrowGodStatus(EPlayer target) |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
local GodStatus emptyStatus; |
||||||
|
|
||||||
|
if (target == none) { |
||||||
|
return emptyStatus; |
||||||
|
} |
||||||
|
for (i = 0; i < godhoodList.length; i += 1) |
||||||
|
{ |
||||||
|
if (target.SameAs(godhoodList[i].target)) { |
||||||
|
return godhoodList[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
return emptyStatus; |
||||||
|
} |
||||||
|
|
||||||
|
defaultproperties |
||||||
|
{ |
||||||
|
TDAMAGE = 0 |
||||||
|
stringConstants(0) = "damage" |
||||||
|
TMOMENTUM = 1 |
||||||
|
stringConstants(1) = "momentum" |
||||||
|
} |
@ -0,0 +1,225 @@ |
|||||||
|
/** |
||||||
|
* Announcer for `ACommandGod`. |
||||||
|
* Copyright 2022 Anton Tarasenko |
||||||
|
*------------------------------------------------------------------------------ |
||||||
|
* This file is part of Acedia. |
||||||
|
* |
||||||
|
* Acedia is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation, version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* Acedia is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
class ACommandGod_Announcer extends CommandAnnouncer |
||||||
|
dependson(ACommandGod); |
||||||
|
|
||||||
|
var private AnnouncementVariations godStatus, newGod, removeGod, sameGod; |
||||||
|
var private AnnouncementVariations changedGod, wasNotGod; |
||||||
|
|
||||||
|
protected function Finalizer() |
||||||
|
{ |
||||||
|
FreeVariations(godStatus); |
||||||
|
FreeVariations(newGod); |
||||||
|
FreeVariations(removeGod); |
||||||
|
FreeVariations(sameGod); |
||||||
|
FreeVariations(changedGod); |
||||||
|
FreeVariations(wasNotGod); |
||||||
|
super.Finalizer(); |
||||||
|
} |
||||||
|
|
||||||
|
public final function AnnounceGodStatus(ACommandGod.GodStatus status) |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
local MutableText statusAsText; |
||||||
|
local array<TextTemplate> templates; |
||||||
|
|
||||||
|
if (!godStatus.initialized) |
||||||
|
{ |
||||||
|
godStatus.initialized = true; |
||||||
|
godStatus.toSelfReport = _.text.MakeTemplate_S( |
||||||
|
"You're %1"); |
||||||
|
godStatus.toOtherReport = _.text.MakeTemplate_S( |
||||||
|
"%%target%% is %1"); |
||||||
|
} |
||||||
|
statusAsText = DisplayStatus(status); |
||||||
|
templates = MakeArray(godStatus); |
||||||
|
for (i = 0; i < templates.length; i += 1) { |
||||||
|
templates[i].Reset().Arg(statusAsText); |
||||||
|
} |
||||||
|
_.memory.Free(statusAsText); |
||||||
|
MakeAnnouncement(godStatus); |
||||||
|
} |
||||||
|
|
||||||
|
public final function AnnounceNewGod(ACommandGod.GodStatus status) |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
local MutableText statusAsText; |
||||||
|
local array<TextTemplate> templates; |
||||||
|
|
||||||
|
if (!newGod.initialized) |
||||||
|
{ |
||||||
|
newGod.initialized = true; |
||||||
|
newGod.toSelfReport = _.text.MakeTemplate_S( |
||||||
|
"You {$TextPositive made} yourself %1"); |
||||||
|
newGod.toSelfPublic = _.text.MakeTemplate_S( |
||||||
|
"%%instigator%% {$TextPositive made} themselves %1"); |
||||||
|
newGod.toOtherReport = _.text.MakeTemplate_S( |
||||||
|
"You {$TextPositive made} %%target%% %1"); |
||||||
|
newGod.toOtherPrivate = _.text.MakeTemplate_S( |
||||||
|
"%%instigator%% {$TextPositive made} you %1"); |
||||||
|
newGod.toOtherPublic = _.text.MakeTemplate_S( |
||||||
|
"%%instigator%% {$TextPositive made} %%target%% %1"); |
||||||
|
} |
||||||
|
statusAsText = DisplayStatus(status); |
||||||
|
templates = MakeArray(newGod); |
||||||
|
for (i = 0; i < templates.length; i += 1) { |
||||||
|
templates[i].Reset().Arg(statusAsText); |
||||||
|
} |
||||||
|
_.memory.Free(statusAsText); |
||||||
|
MakeAnnouncement(newGod); |
||||||
|
} |
||||||
|
|
||||||
|
public final function AnnounceRemoveGod(ACommandGod.GodStatus status) |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
local MutableText statusAsText; |
||||||
|
local array<TextTemplate> templates; |
||||||
|
|
||||||
|
if (!removeGod.initialized) |
||||||
|
{ |
||||||
|
removeGod.initialized = true; |
||||||
|
removeGod.toSelfReport = _.text.MakeTemplate_S( |
||||||
|
"You, %1, {$TextNegative became} a mere {$TextNegative mortal}"); |
||||||
|
removeGod.toSelfPublic = _.text.MakeTemplate_S( |
||||||
|
"%1 %%instigator%% {$TextNegative made} themselves a mere" |
||||||
|
@ "{$TextNegative mortal}"); |
||||||
|
removeGod.toOtherReport = _.text.MakeTemplate_S( |
||||||
|
"%1 %%target%% was {$TextNegative made} a mere" |
||||||
|
@ "{$TextNegative mortal} by you"); |
||||||
|
removeGod.toOtherPrivate = _.text.MakeTemplate_S( |
||||||
|
"You, %1, was {$TextNegative made} a mere {$TextNegative mortal}" |
||||||
|
@ "by %%instigator%%"); |
||||||
|
removeGod.toOtherPublic = _.text.MakeTemplate_S( |
||||||
|
"%1 %%target%% was {$TextNegative made} a mere" |
||||||
|
@ "{$TextNegative mortal} by %%instigator%%"); |
||||||
|
} |
||||||
|
statusAsText = DisplayStatus(status); |
||||||
|
templates = MakeArray(removeGod); |
||||||
|
for (i = 0; i < templates.length; i += 1) { |
||||||
|
templates[i].Reset().Arg(statusAsText); |
||||||
|
} |
||||||
|
_.memory.Free(statusAsText); |
||||||
|
MakeAnnouncement(removeGod); |
||||||
|
} |
||||||
|
|
||||||
|
public final function AnnounceSameGod(ACommandGod.GodStatus status) |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
local MutableText statusAsText; |
||||||
|
local array<TextTemplate> templates; |
||||||
|
|
||||||
|
if (!sameGod.initialized) |
||||||
|
{ |
||||||
|
sameGod.initialized = true; |
||||||
|
sameGod.toSelfReport = _.text.MakeTemplate_S( |
||||||
|
"You are already %1"); |
||||||
|
sameGod.toOtherReport = _.text.MakeTemplate_S( |
||||||
|
"%%target%% is already %1"); |
||||||
|
} |
||||||
|
statusAsText = DisplayStatus(status); |
||||||
|
templates = MakeArray(sameGod); |
||||||
|
for (i = 0; i < templates.length; i += 1) { |
||||||
|
templates[i].Reset().Arg(statusAsText); |
||||||
|
} |
||||||
|
_.memory.Free(statusAsText); |
||||||
|
MakeAnnouncement(sameGod); |
||||||
|
} |
||||||
|
|
||||||
|
public final function AnnounceChangedGod( |
||||||
|
ACommandGod.GodStatus oldStatus, |
||||||
|
ACommandGod.GodStatus newStatus) |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
local MutableText oldStatusAsText, newStatusAsText; |
||||||
|
local array<TextTemplate> templates; |
||||||
|
|
||||||
|
if (!changedGod.initialized) |
||||||
|
{ |
||||||
|
changedGod.initialized = true; |
||||||
|
changedGod.toSelfReport = _.text.MakeTemplate_S( |
||||||
|
"You, %1, {$TextPositive made} yourself %2"); |
||||||
|
changedGod.toSelfPublic = _.text.MakeTemplate_S( |
||||||
|
"%1 %%instigator%% {$TextPositive made} themselves %2"); |
||||||
|
changedGod.toOtherReport = _.text.MakeTemplate_S( |
||||||
|
"You {$TextPositive made} %1 %%target%% into %1"); |
||||||
|
changedGod.toOtherPrivate = _.text.MakeTemplate_S( |
||||||
|
"%%instigator%% {$TextPositive made} you, %1, into %2"); |
||||||
|
changedGod.toOtherPublic = _.text.MakeTemplate_S( |
||||||
|
"%%instigator%% {$TextPositive made} %1 %%target%% into %2"); |
||||||
|
} |
||||||
|
oldStatusAsText = DisplayStatus(oldStatus); |
||||||
|
newStatusAsText = DisplayStatus(newStatus); |
||||||
|
templates = MakeArray(changedGod); |
||||||
|
for (i = 0; i < templates.length; i += 1) { |
||||||
|
templates[i].Reset().Arg(oldStatusAsText).Arg(newStatusAsText); |
||||||
|
} |
||||||
|
_.memory.Free(oldStatusAsText); |
||||||
|
_.memory.Free(newStatusAsText); |
||||||
|
MakeAnnouncement(changedGod); |
||||||
|
} |
||||||
|
|
||||||
|
public final function AnnounceWasNotGod() |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
local array<TextTemplate> templates; |
||||||
|
|
||||||
|
if (!sameGod.initialized) |
||||||
|
{ |
||||||
|
sameGod.initialized = true; |
||||||
|
sameGod.toSelfReport = _.text.MakeTemplate_S( |
||||||
|
"You are already a mere {$TextNegative mortal}"); |
||||||
|
sameGod.toOtherReport = _.text.MakeTemplate_S( |
||||||
|
"%%target%% is already a mere {$TextNegative mortal}"); |
||||||
|
} |
||||||
|
templates = MakeArray(sameGod); |
||||||
|
for (i = 0; i < templates.length; i += 1) { |
||||||
|
templates[i].Reset(); |
||||||
|
} |
||||||
|
MakeAnnouncement(sameGod); |
||||||
|
} |
||||||
|
|
||||||
|
private final function MutableText DisplayStatus(ACommandGod.GodStatus status) |
||||||
|
{ |
||||||
|
local MutableText builder; |
||||||
|
|
||||||
|
builder = _.text.Empty(); |
||||||
|
if (status.target == none) |
||||||
|
{ |
||||||
|
builder.Append(F("a mere {$TextNegative mortal}")); |
||||||
|
return builder; |
||||||
|
} |
||||||
|
if (status.unmovable) { |
||||||
|
builder.Append(F("an {$TextPositive unmovable}, ")); |
||||||
|
} |
||||||
|
else { |
||||||
|
builder.Append(F("a {$TextNeutral simple}, ")); |
||||||
|
} |
||||||
|
if (status.demigod) { |
||||||
|
builder.Append(F("immortal {$TextNeutral demigod}")); |
||||||
|
} |
||||||
|
else { |
||||||
|
builder.Append(F("invincible {$TextPositive god}")); |
||||||
|
} |
||||||
|
return builder; |
||||||
|
} |
||||||
|
|
||||||
|
defaultproperties |
||||||
|
{ |
||||||
|
} |
Loading…
Reference in new issue