- scriptified cht_Give and cht_Take and made them virtual function of PlayerPawn so that this can be better configured for mods that want other options in here.

- improved the class pointer to string cast to print the actual type it describes and not the class pointer's own type.
- fixed: The 'is' operator created non-working code when checking the inheritance of a class pointer, it only worked for objects.
This commit is contained in:
Christoph Oelckers 2017-01-17 17:31:54 +01:00
parent 75d3f42d4f
commit 14f2c39e58
21 changed files with 559 additions and 461 deletions

View file

@ -1326,6 +1326,12 @@ void C_HideConsole ()
}
}
DEFINE_ACTION_FUNCTION(_Console, HideConsole)
{
C_HideConsole();
return 0;
}
static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer)
{
int data1 = ev->data1;

View file

@ -219,6 +219,7 @@ DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionStyle)
DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionAlpha)
DEFINE_FIELD_X(DehInfo, DehInfo, NoAutofreeze)
DEFINE_FIELD_X(DehInfo, DehInfo, BFGCells)
DEFINE_FIELD_X(DehInfo, DehInfo, BlueAC)
// Doom identified pickup items by their sprites. ZDoom prefers to use their
// class type to identify them instead. To support the traditional Doom

View file

@ -1288,6 +1288,19 @@ bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const
return false;
}
DEFINE_ACTION_FUNCTION(FWeaponSlots, LocateWeapon)
{
PARAM_SELF_STRUCT_PROLOGUE(FWeaponSlots);
PARAM_CLASS(weap, AWeapon);
int slot = 0, index = 0;
bool retv = self->LocateWeapon(weap, &slot, &index);
if (numret >= 1) ret[0].SetInt(retv);
if (numret >= 2) ret[1].SetInt(slot);
if (numret >= 3) ret[2].SetInt(index);
return MIN(numret, 3);
}
//===========================================================================
//
// FindMostRecentWeapon

View file

@ -45,6 +45,10 @@
gameinfo_t gameinfo;
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent)
const char *GameNames[17] =
{
NULL, "Doom", "Heretic", NULL, "Hexen", NULL, NULL, NULL, "Strife", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Chex"

View file

@ -148,7 +148,7 @@ struct gameinfo_t
FString translator;
DWORD defaultbloodcolor;
DWORD defaultbloodparticlecolor;
FString backpacktype;
FName backpacktype;
FString statusbar;
FString intermissionMusic;
int intermissionOrder;

View file

@ -50,6 +50,7 @@
#include "a_armor.h"
#include "a_ammo.h"
#include "g_levellocals.h"
#include "virtual.h"
// [RH] Actually handle the cheat. The cheat code in st_stuff.c now just
// writes some bytes to the network data stream, and the network code
@ -324,16 +325,10 @@ void cht_DoCheat (player_t *player, int cheat)
}
else
{
player->mo->Revive();
player->playerstate = PST_LIVE;
player->health = player->mo->health = player->mo->GetDefault()->health;
player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight;
player->mo->flags = player->mo->GetDefault()->flags;
player->mo->flags2 = player->mo->GetDefault()->flags2;
player->mo->flags3 = player->mo->GetDefault()->flags3;
player->mo->flags4 = player->mo->GetDefault()->flags4;
player->mo->flags5 = player->mo->GetDefault()->flags5;
player->mo->flags6 = player->mo->GetDefault()->flags6;
player->mo->flags7 = player->mo->GetDefault()->flags7;
player->mo->renderflags &= ~RF_INVISIBLE;
player->mo->Height = player->mo->GetDefault()->Height;
player->mo->radius = player->mo->GetDefault()->radius;
@ -344,7 +339,6 @@ void cht_DoCheat (player_t *player, int cheat)
{
player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));
}
player->mo->DamageType = NAME_None;
if (player->ReadyWeapon != nullptr)
{
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetUpState());
@ -588,434 +582,24 @@ const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quic
void cht_Give (player_t *player, const char *name, int amount)
{
enum { ALL_NO, ALL_YES, ALL_YESYES } giveall;
int i;
PClassActor *type;
if (player->mo == nullptr) return;
if (player != &players[consoleplayer])
Printf ("%s is a cheater: give %s\n", player->userinfo.GetName(), name);
if (player->mo == NULL || player->health <= 0)
IFVIRTUALPTR(player->mo, APlayerPawn, CheatGive)
{
return;
VMValue params[3] = { player->mo, FString(name), amount };
GlobalVMStack.Call(func, params, 3, nullptr, 0);
}
giveall = ALL_NO;
if (stricmp (name, "all") == 0)
{
giveall = ALL_YES;
}
else if (stricmp (name, "everything") == 0)
{
giveall = ALL_YESYES;
}
if (stricmp (name, "health") == 0)
{
if (amount > 0)
{
player->mo->health += amount;
player->health = player->mo->health;
}
else
{
player->health = player->mo->health = player->mo->GetMaxHealth();
}
}
if (giveall || stricmp (name, "backpack") == 0)
{
// Select the correct type of backpack based on the game
type = PClass::FindActor(gameinfo.backpacktype);
if (type != NULL)
{
player->mo->GiveInventory(static_cast<PClassInventory *>(type), 1, true);
}
if (!giveall)
return;
}
if (giveall || stricmp (name, "ammo") == 0)
{
// 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 (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
PClassActor *type = PClassActor::AllActorClasses[i];
if (type->ParentClass == RUNTIME_CLASS(AAmmo))
{
PClassInventory *atype = static_cast<PClassInventory *>(type);
AInventory *ammo = player->mo->FindInventory(atype);
if (ammo == NULL)
{
ammo = static_cast<AInventory *>(Spawn (atype));
ammo->AttachToOwner (player->mo);
ammo->Amount = ammo->MaxAmount;
}
else if (ammo->Amount < ammo->MaxAmount)
{
ammo->Amount = ammo->MaxAmount;
}
}
}
if (!giveall)
return;
}
if (giveall || stricmp (name, "armor") == 0)
{
if (gameinfo.gametype != GAME_Hexen)
{
ABasicArmorPickup *armor = Spawn<ABasicArmorPickup> ();
armor->SaveAmount = 100*deh.BlueAC;
armor->SavePercent = gameinfo.Armor2Percent > 0? gameinfo.Armor2Percent : 0.5;
if (!armor->CallTryPickup (player->mo))
{
armor->Destroy ();
}
}
else
{
for (i = 0; i < 4; ++i)
{
AHexenArmor *armor = Spawn<AHexenArmor> ();
armor->health = i;
armor->Amount = 0;
if (!armor->CallTryPickup (player->mo))
{
armor->Destroy ();
}
}
}
if (!giveall)
return;
}
if (giveall || stricmp (name, "keys") == 0)
{
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey)))
{
AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]);
if (key->KeyNumber != 0)
{
key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClassActor::AllActorClasses[i])));
if (!key->CallTryPickup (player->mo))
{
key->Destroy ();
}
}
}
}
if (!giveall)
return;
}
if (giveall || stricmp (name, "weapons") == 0)
{
AWeapon *savedpending = player->PendingWeapon;
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
type = PClassActor::AllActorClasses[i];
// Don't give replaced weapons unless the replacement was done by Dehacked.
if (type != RUNTIME_CLASS(AWeapon) &&
type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) &&
(static_cast<PClassActor *>(type)->GetReplacement() == type ||
static_cast<PClassActor *>(type)->GetReplacement()->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup))))
{
// Give the weapon only if it belongs to the current game or
if (player->weapons.LocateWeapon(static_cast<PClassWeapon*>(type), NULL, NULL))
{
AWeapon *def = (AWeapon*)GetDefaultByType (type);
if (giveall == ALL_YESYES || !(def->WeaponFlags & WIF_CHEATNOTWEAPON))
{
player->mo->GiveInventory(static_cast<PClassInventory *>(type), 1, true);
}
}
}
}
player->PendingWeapon = savedpending;
if (!giveall)
return;
}
if (giveall || stricmp (name, "artifacts") == 0)
{
auto pitype = PClass::FindActor(NAME_PuzzleItem);
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
type = PClassActor::AllActorClasses[i];
if (type->IsDescendantOf (RUNTIME_CLASS(AInventory)))
{
AInventory *def = (AInventory*)GetDefaultByType (type);
if (def->Icon.isValid() && def->MaxAmount > 1 &&
!type->IsDescendantOf (pitype) &&
!type->IsDescendantOf (RUNTIME_CLASS(APowerup)) &&
!type->IsDescendantOf (RUNTIME_CLASS(AArmor)))
{
// Do not give replaced items unless using "give everything"
if (giveall == ALL_YESYES || type->GetReplacement() == type)
{
player->mo->GiveInventory(static_cast<PClassInventory *>(type), amount <= 0 ? def->MaxAmount : amount, true);
}
}
}
}
if (!giveall)
return;
}
if (giveall || stricmp (name, "puzzlepieces") == 0)
{
auto pitype = PClass::FindActor(NAME_PuzzleItem);
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
type = PClassActor::AllActorClasses[i];
if (type->IsDescendantOf (pitype))
{
AInventory *def = (AInventory*)GetDefaultByType (type);
if (def->Icon.isValid())
{
// Do not give replaced items unless using "give everything"
if (giveall == ALL_YESYES || type->GetReplacement() == type)
{
player->mo->GiveInventory(static_cast<PClassInventory *>(type), amount <= 0 ? def->MaxAmount : amount, true);
}
}
}
}
if (!giveall)
return;
}
if (giveall)
return;
type = PClass::FindActor(name);
if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AInventory)))
{
if (player == &players[consoleplayer])
Printf ("Unknown item \"%s\"\n", name);
}
else
{
player->mo->GiveInventory(static_cast<PClassInventory *>(type), amount, true);
}
return;
}
void cht_Take (player_t *player, const char *name, int amount)
{
bool takeall;
PClassActor *type;
if (player->mo == nullptr) return;
if (player->mo == NULL || player->health <= 0)
IFVIRTUALPTR(player->mo, APlayerPawn, CheatTake)
{
return;
VMValue params[3] = { player->mo, FString(name), amount };
GlobalVMStack.Call(func, params, 3, nullptr, 0);
}
takeall = (stricmp (name, "all") == 0);
if (!takeall && stricmp (name, "health") == 0)
{
if (player->mo->health - amount <= 0
|| player->health - amount <= 0
|| amount == 0)
{
cht_Suicide (player);
if (player == &players[consoleplayer])
C_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 || stricmp (name, "backpack") == 0)
{
// Take away all types of backpacks the player might own.
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
PClass *type = PClassActor::AllActorClasses[i];
if (type->IsDescendantOf(PClass::FindClass(NAME_BackpackItem)))
{
AInventory *pack = player->mo->FindInventory(static_cast<PClassActor *>(type));
if (pack)
pack->Destroy();
}
}
if (!takeall)
return;
}
if (takeall || stricmp (name, "ammo") == 0)
{
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
PClass *type = PClassActor::AllActorClasses[i];
if (type->ParentClass == RUNTIME_CLASS (AAmmo))
{
AInventory *ammo = player->mo->FindInventory(static_cast<PClassActor *>(type));
if (ammo)
ammo->DepleteOrDestroy();
}
}
if (!takeall)
return;
}
if (takeall || stricmp (name, "armor") == 0)
{
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
type = PClassActor::AllActorClasses[i];
if (type->IsDescendantOf (RUNTIME_CLASS (AArmor)))
{
AInventory *armor = player->mo->FindInventory(static_cast<PClassActor *>(type));
if (armor)
armor->DepleteOrDestroy();
}
}
if (!takeall)
return;
}
if (takeall || stricmp (name, "keys") == 0)
{
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
type = PClassActor::AllActorClasses[i];
if (type->IsDescendantOf (RUNTIME_CLASS (AKey)))
{
AActor *key = player->mo->FindInventory(static_cast<PClassActor *>(type));
if (key)
key->Destroy ();
}
}
if (!takeall)
return;
}
if (takeall || stricmp (name, "weapons") == 0)
{
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
type = PClassActor::AllActorClasses[i];
if (type != RUNTIME_CLASS(AWeapon) &&
type->IsDescendantOf (RUNTIME_CLASS (AWeapon)))
{
AActor *weapon = player->mo->FindInventory(static_cast<PClassActor *>(type));
if (weapon)
weapon->Destroy ();
player->ReadyWeapon = nullptr;
player->PendingWeapon = WP_NOCHANGE;
}
}
if (!takeall)
return;
}
if (takeall || stricmp (name, "artifacts") == 0)
{
auto pitype = PClass::FindActor(NAME_PuzzleItem);
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
type = PClassActor::AllActorClasses[i];
if (type->IsDescendantOf (RUNTIME_CLASS (AInventory)))
{
if (!type->IsDescendantOf (pitype) &&
!type->IsDescendantOf (RUNTIME_CLASS (APowerup)) &&
!type->IsDescendantOf (RUNTIME_CLASS (AArmor)) &&
!type->IsDescendantOf (RUNTIME_CLASS (AWeapon)) &&
!type->IsDescendantOf (RUNTIME_CLASS (AKey)))
{
AActor *artifact = player->mo->FindInventory(static_cast<PClassActor *>(type));
if (artifact)
artifact->Destroy ();
}
}
}
if (!takeall)
return;
}
if (takeall || stricmp (name, "puzzlepieces") == 0)
{
auto pitype = PClass::FindActor(NAME_PuzzleItem);
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{
type = PClassActor::AllActorClasses[i];
if (type->IsDescendantOf (pitype))
{
AActor *puzzlepiece = player->mo->FindInventory(static_cast<PClassActor *>(type));
if (puzzlepiece)
puzzlepiece->Destroy ();
}
}
if (!takeall)
return;
}
if (takeall)
return;
type = PClass::FindActor (name);
if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS (AInventory)))
{
if (player == &players[consoleplayer])
Printf ("Unknown item \"%s\"\n", name);
}
else
{
player->mo->TakeInventory(type, amount ? amount : 1);
}
return;
}
class DSuicider : public DThinker
@ -1070,6 +654,12 @@ void cht_Suicide (player_t *plyr)
}
}
DEFINE_ACTION_FUNCTION(APlayerPawn, CheatSuicide)
{
PARAM_SELF_PROLOGUE(APlayerPawn);
cht_Suicide(self->player);
return 0;
}
CCMD (mdk)
{

View file

@ -1224,22 +1224,6 @@ DEFINE_ACTION_FUNCTION(AActor, CheckInventory)
}
//==========================================================================
//
// State jump function
//
//==========================================================================
DEFINE_ACTION_FUNCTION(AActor, CheckArmorType)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME (type);
PARAM_INT_DEF(amount);
ABasicArmor *armor = (ABasicArmor *)self->FindInventory(NAME_BasicArmor);
ACTION_RETURN_BOOL(armor && armor->ArmorType == type && armor->Amount >= amount);
}
//==========================================================================
//
// Parameterized version of A_Explode

View file

@ -822,11 +822,13 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat)
return result;
}
DEFINE_ACTION_FUNCTION(AActor, Inventory)
DEFINE_ACTION_FUNCTION(AActor, GiveInventory)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT_NOT_NULL(item, AInventory);
ACTION_RETURN_BOOL(self->UseInventory(item));
PARAM_CLASS(type, AInventory);
PARAM_INT(amount);
PARAM_BOOL_DEF(givecheat);
ACTION_RETURN_BOOL(self->GiveInventory(type, amount, givecheat));
}
@ -918,6 +920,16 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate
return result;
}
DEFINE_ACTION_FUNCTION(AActor, TakeInventory)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT_NOT_NULL(item, AInventory);
PARAM_INT(amount);
PARAM_BOOL_DEF(fromdecorate);
PARAM_BOOL_DEF(notakeinfinite);
self->RemoveInventory(item);
return 0;
}
//============================================================================
//

View file

@ -638,6 +638,14 @@ void player_t::SendPitchLimits() const
}
}
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetUserName)
{
PARAM_SELF_STRUCT_PROLOGUE(player_t);
ACTION_RETURN_STRING(self->userinfo.GetName());
}
//===========================================================================
//
// APlayerPawn

View file

@ -4362,9 +4362,8 @@ ExpEmit FxDotCross::Emit(VMFunctionBuilder *build)
FxTypeCheck::FxTypeCheck(FxExpression *l, FxExpression *r)
: FxExpression(EFX_TypeCheck, l->ScriptPosition)
{
left = new FxTypeCast(l, NewPointer(RUNTIME_CLASS(DObject)), false);
right = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), r);
EmitTail = false;
left = l;
right = r;
ValueType = TypeBool;
}
@ -4389,9 +4388,27 @@ FxTypeCheck::~FxTypeCheck()
FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
// This must resolve the cast separately so that it can set the proper type for class descriptors.
RESOLVE(left, ctx);
RESOLVE(right, ctx);
ABORT(right && left);
if (left->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
{
left = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), left);
ClassCheck = true;
}
else
{
left = new FxTypeCast(left, NewPointer(RUNTIME_CLASS(DObject)), false);
ClassCheck = false;
}
right = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), right);
RESOLVE(left, ctx);
RESOLVE(right, ctx);
ABORT(right && left);
return this;
}
@ -4408,7 +4425,8 @@ ExpEmit FxTypeCheck::EmitCommon(VMFunctionBuilder *build)
castee.Free(build);
casttype.Free(build);
ExpEmit ares(build, REGT_POINTER);
build->Emit(casttype.Konst ? OP_DYNCAST_K : OP_DYNCAST_R, ares.RegNum, castee.RegNum, casttype.RegNum);
if (!ClassCheck) build->Emit(casttype.Konst ? OP_DYNCAST_K : OP_DYNCAST_R, ares.RegNum, castee.RegNum, casttype.RegNum);
else build->Emit(casttype.Konst ? OP_DYNCASTC_K : OP_DYNCASTC_R, ares.RegNum, castee.RegNum, casttype.RegNum);
return ares;
}

View file

@ -1086,7 +1086,7 @@ class FxTypeCheck : public FxExpression
public:
FxExpression *left;
FxExpression *right;
bool EmitTail;
bool ClassCheck;
FxTypeCheck(FxExpression*, FxExpression*);
~FxTypeCheck();

View file

@ -788,6 +788,11 @@ void InitThingdef()
PField *dehf = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh);
GlobalSymbols.AddSymbol(dehf);
// set up a variable for the global gameinfo data
PStruct *gistruct = NewNativeStruct("GameInfoStruct", nullptr);
PField *gi = new PField("gameinfo", gistruct, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gameinfo);
GlobalSymbols.AddSymbol(gi);
// set up a variable for the global players array.
PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr);
pstruct->Size = sizeof(player_t);
@ -796,6 +801,9 @@ void InitThingdef()
PField *playerf = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players);
GlobalSymbols.AddSymbol(playerf);
pstruct->AddNativeField("weapons", NewNativeStruct("WeaponSlots", nullptr), myoffsetof(player_t, weapons), VARF_Native);
parray = NewArray(TypeBool, MAXPLAYERS);
playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame);
GlobalSymbols.AddSymbol(playerf);

View file

@ -401,7 +401,7 @@ begin:
OP(MOVEA):
{
ASSERTA(a); ASSERTA(B);
int b = B;
b = B;
reg.a[a] = reg.a[b];
reg.atag[a] = reg.atag[b];
NEXTOP;
@ -409,7 +409,7 @@ begin:
OP(MOVEV2):
{
ASSERTF(a); ASSERTF(B);
int b = B;
b = B;
reg.f[a] = reg.f[b];
reg.f[a + 1] = reg.f[b + 1];
NEXTOP;
@ -417,7 +417,7 @@ begin:
OP(MOVEV3):
{
ASSERTF(a); ASSERTF(B);
int b = B;
b = B;
reg.f[a] = reg.f[b];
reg.f[a + 1] = reg.f[b + 1];
reg.f[a + 2] = reg.f[b + 2];
@ -435,6 +435,18 @@ begin:
reg.a[a] = (reg.a[b] && ((DObject*)(reg.a[b]))->IsKindOf((PClass*)(konsta[C].o))) ? reg.a[b] : nullptr;
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
OP(DYNCASTC_R) :
ASSERTA(a); ASSERTA(B); ASSERTA(C);
b = B;
reg.a[a] = (reg.a[b] && ((PClass*)(reg.a[b]))->IsDescendantOf((PClass*)(reg.a[C]))) ? reg.a[b] : nullptr;
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
OP(DYNCASTC_K) :
ASSERTA(a); ASSERTA(B); ASSERTKA(C);
b = B;
reg.a[a] = (reg.a[b] && ((PClass*)(reg.a[b]))->IsDescendantOf((PClass*)(konsta[C].o))) ? reg.a[b] : nullptr;
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
OP(CAST):
if (C == CAST_I2F)
{
@ -1746,9 +1758,21 @@ static void DoCast(const VMRegisters &reg, const VMFrame *f, int a, int b, int c
break;
case CAST_P2S:
{
ASSERTS(a); ASSERTA(b);
reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? (reg.a[b] == nullptr? "Object" : ((DObject*)reg.a[b])->GetClass()->TypeName.GetChars() ) : "Pointer", reg.a[b]);
break;
if (reg.a[b] == nullptr) reg.s[a] = "null";
else if (reg.atag[b] == ATAG_OBJECT)
{
auto op = static_cast<DObject*>(reg.a[b]);
if (op->IsKindOf(RUNTIME_CLASS(PClass))) reg.s[a].Format("Class<%s>", static_cast<PClass*>(op)->TypeName.GetChars());
else reg.s[a].Format("Object<%p>", ((DObject*)reg.a[b])->GetClass()->TypeName.GetChars());
}
else
{
reg.s[a].Format("%s<%p>", "Pointer", reg.a[b]);
}
break;
}
case CAST_S2I:
ASSERTD(a); ASSERTS(b);

View file

@ -86,6 +86,8 @@ xx(CAST, cast, CAST, NOP, 0, 0), // xA = xB, conversion specified by C
xx(CASTB, castb, CAST, NOP, 0, 0), // xA = !!xB, type specified by C
xx(DYNCAST_R, dyncast, RPRPRP, NOP, 0, 0), // aA = dyn_cast<aC>(aB);
xx(DYNCAST_K, dyncast, RPRPKP, NOP, 0, 0), // aA = dyn_cast<aKC>(aB);
xx(DYNCASTC_R, dyncastc, RPRPRP, NOP, 0, 0), // aA = dyn_cast<aC>(aB); for class types
xx(DYNCASTC_K, dyncastc, RPRPKP, NOP, 0, 0), // aA = dyn_cast<aKC>(aB);
// Control flow.
xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++

View file

@ -15,6 +15,7 @@
#include "zscript/inventory/powerups.txt"
#include "zscript/shared/player.txt"
#include "zscript/shared/player_cheat.txt"
#include "zscript/shared/morph.txt"
#include "zscript/shared/botstuff.txt"
#include "zscript/shared/sharedmisc.txt"

View file

@ -487,6 +487,8 @@ class Actor : Thinker native
native void AddInventory(Inventory inv);
native void RemoveInventory(Inventory inv);
native void ClearInventory();
native bool GiveInventory(class<Inventory> type, int amount, bool givecheat = false);
native bool TakeInventory(class<Inventory> itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false);
native Inventory FindInventory(class<Inventory> itemtype, bool subclass = false);
native Inventory GiveInventoryType(class<Inventory> itemtype);
native Inventory DropInventory (Inventory item);

View file

@ -106,11 +106,15 @@ extend class Actor
//==========================================================================
//
//
// rather pointless these days to do it this way.
//
//==========================================================================
native bool CheckArmorType(name Type, int amount = 1);
bool CheckArmorType(name Type, int amount = 1)
{
let myarmor = BasicArmor(FindInventory("BasicArmor"));
return myarmor != null && myarmor.ArmorType == type && myarmor.Amount >= amount;
}
action state A_JumpIfArmorType(name Type, statelabel label, int amount = 1)
{

View file

@ -32,11 +32,23 @@ struct TexMan
native static TextureID CheckForTexture(String name, int usetype, int flags = TryAny);
}
struct Screen
struct Screen native
{
native static void DrawHUDTexture(TextureID tex, double x, double y);
}
struct Console native
{
native static void HideConsole();
}
struct GameInfoStruct native
{
// will be extended as needed.
native Name backpacktype;
native double Armor2Percent;
}
class Object native
{
native bool bDestroyed;
@ -200,6 +212,7 @@ struct DehInfo native
native double ExplosionAlpha;
native int NoAutofreeze;
native int BFGCells;
native int BlueAC;
}
struct State native

View file

@ -125,3 +125,7 @@ class WeaponPiece : Inventory native
}
}
struct WeaponSlots native
{
native bool, int, int LocateWeapon(class<Weapon> weap);
}

View file

@ -258,11 +258,12 @@ struct PlayerInfo native // this is what internally is known as player_t
native Actor ConversationPC;
native double ConversationNPCAngle;
native bool ConversationFaceTalker;
//native WeaponSlots weapons; <- defined internally
/* these are not doable yet
ticcmd_t cmd;
usercmd_t original_cmd;
userinfo_t userinfo; // [RH] who is this?
FWeaponSlots weapons;
userinfo_t userinfo;
*/
@ -276,5 +277,6 @@ FWeaponSlots weapons;
native PSprite FindPSprite(int id);
native void SetLogNumber (int text);
native void SetLogText (String text);
native String GetUserName();
}

View file

@ -0,0 +1,402 @@
/*
** 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(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();
}
}
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)
{
type = (class<Inventory>)(AllActorClasses[i]);
if (type != null && type.GetParentClass() == "Ammo")
{
let ammoitem = FindInventory(type);
if (ammoitem == NULL)
{
ammoitem = Inventory(Spawn (type));
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 (GameType() != GAME_Hexen)
{
let armoritem = BasicArmorPickup(Spawn("BasicArmorPickup"));
armoritem.SaveAmount = 100*deh.BlueAC;
armoritem.SavePercent = gameinfo.Armor2Percent > 0? gameinfo.Armor2Percent : 0.5;
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")
{
readonly<Key> keyitem = GetDefaultByType ((class<Key>)(AllActorClasses[i]));
if (keyitem.KeyNumber != 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(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.Destroy();
}
}
}
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(format("Unknown item \"%s\"\n", name));
}
else
{
TakeInventory(type, max(amount, 1));
}
return;
}
}