mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-12-12 05:31:58 +00:00
478 lines
11 KiB
Text
478 lines
11 KiB
Text
/*
|
|
** player_cheat.txt
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright 1999-2016 Randy Heit
|
|
** Copyright 2006-2017 Christoph Oelckers
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**---------------------------------------------------------------------------
|
|
**
|
|
*/
|
|
|
|
extend class PlayerPawn
|
|
{
|
|
enum EAll
|
|
{
|
|
ALL_NO,
|
|
ALL_YES,
|
|
ALL_YESYES
|
|
}
|
|
|
|
native void CheatSuicide();
|
|
|
|
virtual void CheatGive (String name, int amount)
|
|
{
|
|
int i;
|
|
Class<Inventory> type;
|
|
let player = self.player;
|
|
|
|
if (PlayerNumber() != consoleplayer)
|
|
A_Log(String.Format ("%s is a cheater: give %s\n", player.GetUserName(), name));
|
|
|
|
if (player.mo == NULL || player.health <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int giveall = ALL_NO;
|
|
if (name ~== "all")
|
|
{
|
|
giveall = ALL_YES;
|
|
}
|
|
else if (name ~== "everything")
|
|
{
|
|
giveall = ALL_YESYES;
|
|
}
|
|
|
|
if (name ~== "health")
|
|
{
|
|
if (amount > 0)
|
|
{
|
|
health += amount;
|
|
player.health = health;
|
|
}
|
|
else
|
|
{
|
|
player.health = health = GetMaxHealth(true);
|
|
}
|
|
}
|
|
|
|
if (giveall || name ~== "backpack")
|
|
{
|
|
// Select the correct type of backpack based on the game
|
|
type = (class<Inventory>)(gameinfo.backpacktype);
|
|
if (type != NULL)
|
|
{
|
|
GiveInventory(type, 1, true);
|
|
}
|
|
|
|
if (!giveall)
|
|
return;
|
|
}
|
|
|
|
if (giveall || name ~== "ammo")
|
|
{
|
|
// Find every unique type of ammo. Give it to the player if
|
|
// he doesn't have it already, and set each to its maximum.
|
|
for (i = 0; i < AllActorClasses.Size(); ++i)
|
|
{
|
|
let ammotype = (class<Ammo>)(AllActorClasses[i]);
|
|
|
|
if (ammotype && GetDefaultByType(ammotype).GetParentAmmo() == ammotype)
|
|
{
|
|
let ammoitem = FindInventory(ammotype);
|
|
if (ammoitem == NULL)
|
|
{
|
|
ammoitem = Inventory(Spawn (ammotype));
|
|
ammoitem.AttachToOwner (self);
|
|
ammoitem.Amount = ammoitem.MaxAmount;
|
|
}
|
|
else if (ammoitem.Amount < ammoitem.MaxAmount)
|
|
{
|
|
ammoitem.Amount = ammoitem.MaxAmount;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!giveall)
|
|
return;
|
|
}
|
|
|
|
if (giveall || name ~== "armor")
|
|
{
|
|
if (gameinfo.gametype != GAME_Hexen)
|
|
{
|
|
let armoritem = BasicArmorPickup(Spawn("BasicArmorPickup"));
|
|
armoritem.SaveAmount = 100*deh.BlueAC;
|
|
armoritem.SavePercent = gameinfo.Armor2Percent > 0 ? gameinfo.Armor2Percent * 100 : 50;
|
|
if (!armoritem.CallTryPickup (self))
|
|
{
|
|
armoritem.Destroy ();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 4; ++i)
|
|
{
|
|
let armoritem = Inventory(Spawn("HexenArmor"));
|
|
armoritem.health = i;
|
|
armoritem.Amount = 0;
|
|
if (!armoritem.CallTryPickup (self))
|
|
{
|
|
armoritem.Destroy ();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!giveall)
|
|
return;
|
|
}
|
|
|
|
if (giveall || name ~== "keys")
|
|
{
|
|
for (int i = 0; i < AllActorClasses.Size(); ++i)
|
|
{
|
|
if (AllActorClasses[i] is "Key")
|
|
{
|
|
let keyitem = GetDefaultByType (AllActorClasses[i]);
|
|
if (keyitem.special1 != 0)
|
|
{
|
|
let item = Inventory(Spawn(AllActorClasses[i]));
|
|
if (!item.CallTryPickup (self))
|
|
{
|
|
item.Destroy ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!giveall)
|
|
return;
|
|
}
|
|
|
|
if (giveall || name ~== "weapons")
|
|
{
|
|
let savedpending = player.PendingWeapon;
|
|
for (i = 0; i < AllActorClasses.Size(); ++i)
|
|
{
|
|
let type = (class<Weapon>)(AllActorClasses[i]);
|
|
if (type != null && type != "Weapon")
|
|
{
|
|
// Don't give replaced weapons unless the replacement was done by Dehacked.
|
|
let rep = GetReplacement(type);
|
|
if (rep == type || rep is "DehackedPickup")
|
|
{
|
|
// Give the weapon only if it is set in a weapon slot.
|
|
if (player.weapons.LocateWeapon(type))
|
|
{
|
|
readonly<Weapon> def = GetDefaultByType (type);
|
|
if (giveall == ALL_YESYES || !def.bCheatNotWeapon)
|
|
{
|
|
GiveInventory(type, 1, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
player.PendingWeapon = savedpending;
|
|
|
|
if (!giveall)
|
|
return;
|
|
}
|
|
|
|
if (giveall || name ~== "artifacts")
|
|
{
|
|
for (i = 0; i < AllActorClasses.Size(); ++i)
|
|
{
|
|
type = (class<Inventory>)(AllActorClasses[i]);
|
|
if (type!= null)
|
|
{
|
|
let def = GetDefaultByType (type);
|
|
if (def.Icon.isValid() && def.MaxAmount > 1 &&
|
|
!(type is "PuzzleItem") && !(type is "Powerup") && !(type is "Ammo") && !(type is "Armor"))
|
|
{
|
|
// Do not give replaced items unless using "give everything"
|
|
if (giveall == ALL_YESYES || GetReplacement(type) == type)
|
|
{
|
|
GiveInventory(type, amount <= 0 ? def.MaxAmount : amount, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!giveall)
|
|
return;
|
|
}
|
|
|
|
if (giveall || name ~== "puzzlepieces")
|
|
{
|
|
for (i = 0; i < AllActorClasses.Size(); ++i)
|
|
{
|
|
let type = (class<PuzzleItem>)(AllActorClasses[i]);
|
|
if (type != null)
|
|
{
|
|
let def = GetDefaultByType (type);
|
|
if (def.Icon.isValid())
|
|
{
|
|
// Do not give replaced items unless using "give everything"
|
|
if (giveall == ALL_YESYES || GetReplacement(type) == type)
|
|
{
|
|
GiveInventory(type, amount <= 0 ? def.MaxAmount : amount, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!giveall)
|
|
return;
|
|
}
|
|
|
|
if (giveall)
|
|
return;
|
|
|
|
type = name;
|
|
if (type == NULL)
|
|
{
|
|
if (PlayerNumber() == consoleplayer)
|
|
A_Log(String.Format("Unknown item \"%s\"\n", name));
|
|
}
|
|
else
|
|
{
|
|
GiveInventory(type, amount, true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void CheatTakeType(class<Inventory> deletetype)
|
|
{
|
|
for (int i = 0; i < AllActorClasses.Size(); ++i)
|
|
{
|
|
let type = (class<Inventory>)(AllActorClasses[i]);
|
|
|
|
if (type != null && type is deletetype)
|
|
{
|
|
let pack = FindInventory(type);
|
|
if (pack) pack.DepleteOrDestroy();
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual void CheatTake (String name, int amount)
|
|
{
|
|
bool takeall;
|
|
Class<Inventory> type;
|
|
let player = self.player;
|
|
|
|
|
|
if (player.mo == NULL || player.health <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
takeall = name ~== "all";
|
|
|
|
if (!takeall && name ~== "health")
|
|
{
|
|
if (player.mo.health - amount <= 0
|
|
|| player.health - amount <= 0
|
|
|| amount == 0)
|
|
{
|
|
|
|
CheatSuicide ();
|
|
|
|
if (PlayerNumber() == consoleplayer)
|
|
Console.HideConsole ();
|
|
|
|
return;
|
|
}
|
|
|
|
if (amount > 0)
|
|
{
|
|
if (player.mo)
|
|
{
|
|
player.mo.health -= amount;
|
|
player.health = player.mo.health;
|
|
}
|
|
else
|
|
{
|
|
player.health -= amount;
|
|
}
|
|
}
|
|
|
|
if (!takeall)
|
|
return;
|
|
}
|
|
|
|
if (takeall || name ~== "backpack")
|
|
{
|
|
CheatTakeType("BackpackItem");
|
|
if (!takeall)
|
|
return;
|
|
}
|
|
|
|
if (takeall || name ~== "ammo")
|
|
{
|
|
CheatTakeType("Ammo");
|
|
if (!takeall)
|
|
return;
|
|
}
|
|
|
|
if (takeall || name ~== "armor")
|
|
{
|
|
CheatTakeType("Armor");
|
|
if (!takeall)
|
|
return;
|
|
}
|
|
|
|
if (takeall || name ~== "keys")
|
|
{
|
|
CheatTakeType("Key");
|
|
if (!takeall)
|
|
return;
|
|
}
|
|
|
|
if (takeall || name ~== "weapons")
|
|
{
|
|
CheatTakeType("Weapon");
|
|
CheatTakeType("WeaponHolder");
|
|
player.ReadyWeapon = null;
|
|
player.PendingWeapon = WP_NOCHANGE;
|
|
|
|
if (!takeall)
|
|
return;
|
|
}
|
|
|
|
if (takeall || name ~== "artifacts")
|
|
{
|
|
for (int i = 0; i < AllActorClasses.Size(); ++i)
|
|
{
|
|
type = (class<Inventory>)(AllActorClasses[i]);
|
|
if (type!= null && !(type is "PuzzleItem") && !(type is "Powerup") && !(type is "Ammo") && !(type is "Armor"))
|
|
{
|
|
let pack = FindInventory(type);
|
|
if (pack) pack.Destroy();
|
|
}
|
|
}
|
|
if (!takeall)
|
|
return;
|
|
}
|
|
|
|
if (takeall || name ~== "puzzlepieces")
|
|
{
|
|
CheatTakeType("PuzzleItem");
|
|
if (!takeall)
|
|
return;
|
|
}
|
|
|
|
if (takeall)
|
|
return;
|
|
|
|
type = name;
|
|
if (type == NULL)
|
|
{
|
|
if (PlayerNumber() == consoleplayer)
|
|
A_Log(String.Format("Unknown item \"%s\"\n", name));
|
|
}
|
|
else
|
|
{
|
|
TakeInventory(type, max(amount, 1));
|
|
}
|
|
return;
|
|
}
|
|
|
|
virtual void CheatSetInv(String strng, int amount, bool beyond)
|
|
{
|
|
if (!(strng ~== "health"))
|
|
{
|
|
if (amount <= 0)
|
|
{
|
|
CheatSuicide();
|
|
return;
|
|
}
|
|
if (!beyond) amount = MIN(amount, player.mo.GetMaxHealth(true));
|
|
player.health = player.mo.health = amount;
|
|
}
|
|
else
|
|
{
|
|
class<Inventory> item = strng;
|
|
if (item != null)
|
|
{
|
|
player.mo.SetInventory(item, amount, beyond);
|
|
return;
|
|
}
|
|
Console.Printf("Unknown item \"%s\"\n", strng);
|
|
}
|
|
}
|
|
|
|
|
|
virtual String CheatMorph(class<PlayerPawn> morphClass, bool quickundo)
|
|
{
|
|
let oldclass = GetClass();
|
|
|
|
// Set the standard morph style for the current game
|
|
int style = MRF_UNDOBYTOMEOFPOWER;
|
|
if (gameinfo.gametype == GAME_Hexen) style |= MRF_UNDOBYCHAOSDEVICE;
|
|
|
|
if (player.morphTics)
|
|
{
|
|
if (UndoPlayerMorph (player))
|
|
{
|
|
if (!quickundo && oldclass != morphclass && MorphPlayer (player, morphclass, 0, style))
|
|
{
|
|
return StringTable.Localize("$TXT_STRANGER");
|
|
}
|
|
return StringTable.Localize("$TXT_NOTSTRANGE");
|
|
}
|
|
}
|
|
else if (MorphPlayer (player, morphclass, 0, style))
|
|
{
|
|
return StringTable.Localize("$TXT_STRANGE");
|
|
}
|
|
return "";
|
|
}
|
|
|
|
virtual void CheatTakeWeaps()
|
|
{
|
|
if (player.morphTics || health <= 0)
|
|
{
|
|
return;
|
|
}
|
|
// Do not mass-delete directly from the linked list. That can cause problems.
|
|
Array<Inventory> collect;
|
|
// Take away all weapons that are either non-wimpy or use ammo.
|
|
for(let item = Inv; item; item = item.Inv)
|
|
{
|
|
let weap = Weapon(item);
|
|
if (weap && (!weap.bWimpy_Weapon || weap.AmmoType1 != null))
|
|
{
|
|
collect.Push(item);
|
|
}
|
|
}
|
|
// Destroy them in a second loop. We have to look out for indirect destructions here as will happen with powered up weapons.
|
|
for(int i = 0; i < collect.Size(); i++)
|
|
{
|
|
let item = collect[i];
|
|
if (item) item.Destroy();
|
|
}
|
|
}
|
|
}
|