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