|
|
|
/**
|
|
|
|
* 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 bool connectedToSignal;
|
|
|
|
var private array<GodStatus> godhoodList;
|
|
|
|
|
|
|
|
var private ACommandGod_Announcer announcer;
|
|
|
|
|
|
|
|
var private const int TDAMAGE, TMOMENTUM;
|
|
|
|
|
|
|
|
protected function Finalizer()
|
|
|
|
{
|
|
|
|
connectedToSignal = false;
|
|
|
|
_server.kf.health.OnDamage(self).Disconnect();
|
|
|
|
_.memory.Free(announcer);
|
|
|
|
super.Finalizer();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function BuildData(CommandDataBuilder builder)
|
|
|
|
{
|
|
|
|
builder.Group(P("gameplay"));
|
|
|
|
builder.Summary(P("Command for making player immortal."));
|
|
|
|
builder.RequireTarget();
|
|
|
|
builder.Describe(P("Gives targeted players god status, making them"
|
|
|
|
@ "invincible."));
|
|
|
|
builder.SubCommand(P("list"));
|
|
|
|
builder.Describe(P("Reports godhood status of targeted players."));
|
|
|
|
builder.SubCommand(P("strip"));
|
|
|
|
builder.Describe(P("Strips targeted players from the godhood status."));
|
|
|
|
builder.Option(P("demi"));
|
|
|
|
builder.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"));
|
|
|
|
builder.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'));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function ExecutedFor(
|
|
|
|
EPlayer target,
|
|
|
|
CallData arguments,
|
|
|
|
EPlayer instigator,
|
|
|
|
CommandPermissions permissions
|
|
|
|
) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
UpdateHealthSignalConnection();
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
UpdateHealthSignalConnection();
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
private final function UpdateHealthSignalConnection()
|
|
|
|
{
|
|
|
|
if (connectedToSignal && godhoodList.length <= 0)
|
|
|
|
{
|
|
|
|
_server.kf.health.OnDamage(self).Disconnect();
|
|
|
|
connectedToSignal = false;
|
|
|
|
}
|
|
|
|
if (!connectedToSignal && godhoodList.length > 0)
|
|
|
|
{
|
|
|
|
connectedToSignal = true;
|
|
|
|
_server.kf.health.OnDamage(self).connect = ProtectDivines;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
defaultproperties
|
|
|
|
{
|
|
|
|
preferredName = "god"
|
|
|
|
TDAMAGE = 0
|
|
|
|
stringConstants(0) = "damage"
|
|
|
|
TMOMENTUM = 1
|
|
|
|
stringConstants(1) = "momentum"
|
|
|
|
}
|