This commit is contained in:
Rachael Alexanderson 2017-01-18 21:15:08 -05:00
commit 9333ce1888
63 changed files with 1354 additions and 1931 deletions

View file

@ -1195,11 +1195,9 @@ set (PCH_SOURCES
w_wad.cpp w_wad.cpp
wi_stuff.cpp wi_stuff.cpp
zstrformat.cpp zstrformat.cpp
g_inventory/a_ammo.cpp
g_inventory/a_armor.cpp g_inventory/a_armor.cpp
g_inventory/a_keys.cpp g_inventory/a_keys.cpp
g_inventory/a_pickups.cpp g_inventory/a_pickups.cpp
g_inventory/a_weaponpiece.cpp
g_inventory/a_weapons.cpp g_inventory/a_weapons.cpp
g_strife/strife_sbar.cpp g_strife/strife_sbar.cpp
g_shared/a_action.cpp g_shared/a_action.cpp

View file

@ -721,7 +721,7 @@ public:
// Finds the first item of a particular type. // Finds the first item of a particular type.
AInventory *FindInventory (PClassActor *type, bool subclass=false); AInventory *FindInventory (PClassActor *type, bool subclass=false);
AInventory *FindInventory (FName type); AInventory *FindInventory (FName type, bool subclass = false);
template<class T> T *FindInventory () template<class T> T *FindInventory ()
{ {
return static_cast<T *> (FindInventory (RUNTIME_TEMPLATE_CLASS(T))); return static_cast<T *> (FindInventory (RUNTIME_TEMPLATE_CLASS(T)));

View file

@ -2740,8 +2740,8 @@ void AM_drawKeys ()
mpoint_t p; mpoint_t p;
DAngle angle; DAngle angle;
TThinkerIterator<AKey> it; TThinkerIterator<AInventory> it(NAME_Key);
AKey *key; AInventory *key;
while ((key = it.Next()) != NULL) while ((key = it.Next()) != NULL)
{ {
@ -2853,7 +2853,7 @@ void AM_drawThings ()
// Find the key's own color. // Find the key's own color.
// Only works correctly if single-key locks have lower numbers than any-key locks. // Only works correctly if single-key locks have lower numbers than any-key locks.
// That is the case for all default keys, however. // That is the case for all default keys, however.
if (t->IsKindOf(RUNTIME_CLASS(AKey))) if (t->IsKindOf(PClass::FindActor(NAME_Key)))
{ {
if (G_SkillProperty(SKILLP_EasyKey)) if (G_SkillProperty(SKILLP_EasyKey))
{ {
@ -2863,7 +2863,7 @@ void AM_drawThings ()
else if (am_showkeys) else if (am_showkeys)
{ {
int P_GetMapColorForKey (AInventory * key); int P_GetMapColorForKey (AInventory * key);
int c = P_GetMapColorForKey(static_cast<AKey *>(t)); int c = P_GetMapColorForKey(static_cast<AInventory *>(t));
if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c)); if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c));
else color = AMColors[AMColors.ThingColor_CountItem]; else color = AMColors[AMColors.ThingColor_CountItem];
@ -3048,7 +3048,7 @@ void AM_Drawer ()
return; return;
bool allmap = (level.flags2 & LEVEL2_ALLMAP) != 0; bool allmap = (level.flags2 & LEVEL2_ALLMAP) != 0;
bool allthings = allmap && players[consoleplayer].mo->FindInventory(PClass::FindActor(NAME_PowerScanner), true) != nullptr; bool allthings = allmap && players[consoleplayer].mo->FindInventory(NAME_PowerScanner, true) != nullptr;
if (am_portaloverlay) if (am_portaloverlay)
{ {

View file

@ -21,7 +21,6 @@
#include "d_event.h" #include "d_event.h"
#include "d_player.h" #include "d_player.h"
#include "vectors.h" #include "vectors.h"
#include "a_ammo.h"
static FRandom pr_botmove ("BotMove"); static FRandom pr_botmove ("BotMove");
@ -346,12 +345,12 @@ void DBot::WhatToGet (AActor *item)
} }
} }
} }
else if (item->IsKindOf (RUNTIME_CLASS(AAmmo))) else if (item->IsKindOf (PClass::FindActor(NAME_Ammo)))
{ {
AAmmo *ammo = static_cast<AAmmo *> (item); auto ac = PClass::FindActor(NAME_Ammo);
PClassActor *parent = ammo->GetParentAmmo (); auto parent = item->GetClass();
while (parent->ParentClass != ac) parent = (PClassActor*)(parent->ParentClass);
AInventory *holdingammo = player->mo->FindInventory(parent); AInventory *holdingammo = player->mo->FindInventory(parent);
if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount) if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount)
{ {
return; return;

View file

@ -31,7 +31,6 @@
#include "templates.h" #include "templates.h"
#include "d_net.h" #include "d_net.h"
#include "d_event.h" #include "d_event.h"
#include "a_armor.h"
#define QUEUESIZE 128 #define QUEUESIZE 128
#define MESSAGESIZE 128 #define MESSAGESIZE 128
@ -434,7 +433,7 @@ static bool DoSubstitution (FString &out, const char *in)
{ {
if (strnicmp(a, "armor", 5) == 0) if (strnicmp(a, "armor", 5) == 0)
{ {
AInventory *armor = player->mo->FindInventory<ABasicArmor>(); AInventory *armor = player->mo->FindInventory(NAME_BasicArmor);
out.AppendFormat("%d", armor != NULL ? armor->Amount : 0); out.AppendFormat("%d", armor != NULL ? armor->Amount : 0);
} }
} }

View file

@ -74,8 +74,6 @@
#include "info.h" #include "info.h"
#include "v_text.h" #include "v_text.h"
#include "vmbuilder.h" #include "vmbuilder.h"
#include "a_armor.h"
#include "a_ammo.h"
// [SO] Just the way Randy said to do it :) // [SO] Just the way Randy said to do it :)
// [RH] Made this CVAR_SERVERINFO // [RH] Made this CVAR_SERVERINFO
@ -1536,7 +1534,7 @@ static int PatchSprite (int sprNum)
static int PatchAmmo (int ammoNum) static int PatchAmmo (int ammoNum)
{ {
PClassActor *ammoType = NULL; PClassActor *ammoType = NULL;
AAmmo *defaultAmmo = NULL; AInventory *defaultAmmo = NULL;
int result; int result;
int oldclip; int oldclip;
int dummy; int dummy;
@ -1549,7 +1547,7 @@ static int PatchAmmo (int ammoNum)
ammoType = AmmoNames[ammoNum]; ammoType = AmmoNames[ammoNum];
if (ammoType != NULL) if (ammoType != NULL)
{ {
defaultAmmo = (AAmmo *)GetDefaultByType (ammoType); defaultAmmo = (AInventory*)GetDefaultByType (ammoType);
if (defaultAmmo != NULL) if (defaultAmmo != NULL)
{ {
max = &defaultAmmo->MaxAmount; max = &defaultAmmo->MaxAmount;
@ -1575,8 +1573,8 @@ static int PatchAmmo (int ammoNum)
// Calculate the new backpack-given amounts for this ammo. // Calculate the new backpack-given amounts for this ammo.
if (ammoType != NULL) if (ammoType != NULL)
{ {
defaultAmmo->BackpackMaxAmount = defaultAmmo->MaxAmount * 2; defaultAmmo->IntVar("BackpackMaxAmount") = defaultAmmo->MaxAmount * 2;
defaultAmmo->BackpackAmount = defaultAmmo->Amount; defaultAmmo->IntVar("BackpackAmount") = defaultAmmo->Amount;
} }
// Fix per-ammo/max-ammo amounts for descendants of the base ammo class // Fix per-ammo/max-ammo amounts for descendants of the base ammo class
@ -1591,7 +1589,7 @@ static int PatchAmmo (int ammoNum)
if (type->IsDescendantOf (ammoType)) if (type->IsDescendantOf (ammoType))
{ {
defaultAmmo = (AAmmo *)GetDefaultByType (type); defaultAmmo = (AInventory *)GetDefaultByType (type);
defaultAmmo->MaxAmount = *max; defaultAmmo->MaxAmount = *max;
defaultAmmo->Amount = Scale (defaultAmmo->Amount, *per, oldclip); defaultAmmo->Amount = Scale (defaultAmmo->Amount, *per, oldclip);
} }
@ -1673,7 +1671,7 @@ static int PatchWeapon (int weapNum)
info->AmmoType1 = (PClassInventory*)AmmoNames[val]; info->AmmoType1 = (PClassInventory*)AmmoNames[val];
if (info->AmmoType1 != NULL) if (info->AmmoType1 != NULL)
{ {
info->AmmoGive1 = ((AAmmo*)GetDefaultByType (info->AmmoType1))->Amount * 2; info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2;
if (info->AmmoUse1 == 0) if (info->AmmoUse1 == 0)
{ {
info->AmmoUse1 = 1; info->AmmoUse1 = 1;
@ -1949,26 +1947,24 @@ static int PatchMisc (int dummy)
// Update default item properties by patching the affected items // Update default item properties by patching the affected items
// Note: This won't have any effect on DECORATE derivates of these items! // Note: This won't have any effect on DECORATE derivates of these items!
ABasicArmorPickup *armor;
armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("GreenArmor")); auto armor = GetDefaultByName ("GreenArmor");
if (armor!=NULL) if (armor!=NULL)
{ {
armor->SaveAmount = 100 * deh.GreenAC; armor->IntVar(NAME_SaveAmount) = 100 * deh.GreenAC;
armor->SavePercent = deh.GreenAC == 1 ? 0.33335 : 0.5; armor->FloatVar(NAME_SavePercent) = deh.GreenAC == 1 ? 0.33335 : 0.5;
} }
armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("BlueArmor")); armor = GetDefaultByName ("BlueArmor");
if (armor!=NULL) if (armor!=NULL)
{ {
armor->SaveAmount = 100 * deh.BlueAC; armor->IntVar(NAME_SaveAmount) = 100 * deh.BlueAC;
armor->SavePercent = deh.BlueAC == 1 ? 0.33335 : 0.5; armor->FloatVar(NAME_SavePercent) = deh.BlueAC == 1 ? 0.33335 : 0.5;
} }
ABasicArmorBonus *barmor; auto barmor = GetDefaultByName ("ArmorBonus");
barmor = static_cast<ABasicArmorBonus *> (GetDefaultByName ("ArmorBonus"));
if (barmor!=NULL) if (barmor!=NULL)
{ {
barmor->MaxSaveAmount = deh.MaxArmor; barmor->IntVar("MaxSaveAmount") = deh.MaxArmor;
} }
AInventory *health; AInventory *health;
@ -2930,7 +2926,7 @@ static bool LoadDehSupp ()
else else
{ {
auto cls = PClass::FindActor(sc.String); auto cls = PClass::FindActor(sc.String);
if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(AAmmo))) if (cls == NULL || !cls->IsDescendantOf(PClass::FindActor(NAME_Ammo)))
{ {
sc.ScriptError("Unknown ammo type '%s'", sc.String); sc.ScriptError("Unknown ammo type '%s'", sc.String);
} }
@ -3184,7 +3180,7 @@ bool ADehackedPickup::ShouldRespawn ()
void ADehackedPickup::PlayPickupSound (AActor *toucher) void ADehackedPickup::PlayPickupSound (AActor *toucher)
{ {
if (RealPickup != nullptr) if (RealPickup != nullptr)
RealPickup->PlayPickupSound (toucher); RealPickup->CallPlayPickupSound (toucher);
} }
void ADehackedPickup::DoPickupSpecial (AActor *toucher) void ADehackedPickup::DoPickupSpecial (AActor *toucher)

View file

@ -177,11 +177,6 @@ public:
}; };
class APlayerChunk : public APlayerPawn
{
DECLARE_CLASS (APlayerChunk, APlayerPawn)
};
// //
// PlayerPawn flags // PlayerPawn flags
// //

View file

@ -571,7 +571,7 @@ DEFINE_ACTION_FUNCTION(DObject, GetClassName)
void *DObject::ScriptVar(FName field, PType *type) void *DObject::ScriptVar(FName field, PType *type)
{ {
auto sym = dyn_cast<PField>(GetClass()->Symbols.FindSymbol(field, true)); auto sym = dyn_cast<PField>(GetClass()->Symbols.FindSymbol(field, true));
if (sym && sym->Type == type) if (sym && (sym->Type == type || type == nullptr))
{ {
return (((char*)this) + sym->Offset); return (((char*)this) + sym->Offset);
} }

View file

@ -482,6 +482,7 @@ public:
PalEntry &ColorVar(FName field); PalEntry &ColorVar(FName field);
FName &NameVar(FName field); FName &NameVar(FName field);
double &FloatVar(FName field); double &FloatVar(FName field);
template<class T> T*& PointerVar(FName field);
// If you need to replace one object with another and want to // If you need to replace one object with another and want to
// change any pointers from the old object to the new object, // change any pointers from the old object to the new object,

View file

@ -45,7 +45,6 @@
#include "autosegs.h" #include "autosegs.h"
#include "v_text.h" #include "v_text.h"
#include "a_pickups.h" #include "a_pickups.h"
#include "a_weaponpiece.h"
#include "d_player.h" #include "d_player.h"
#include "doomerrors.h" #include "doomerrors.h"
#include "fragglescript/t_fs.h" #include "fragglescript/t_fs.h"

View file

@ -1093,5 +1093,9 @@ inline double &DObject::FloatVar(FName field)
return *(double*)ScriptVar(field, TypeFloat64); return *(double*)ScriptVar(field, TypeFloat64);
} }
template<class T>
inline T *&DObject::PointerVar(FName field)
{
return *(T**)ScriptVar(field, nullptr); // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle.
}
#endif #endif

View file

@ -69,7 +69,6 @@
#include "p_setup.h" #include "p_setup.h"
#include "p_spec.h" #include "p_spec.h"
#include "r_utility.h" #include "r_utility.h"
#include "a_ammo.h"
#include "math/cmath.h" #include "math/cmath.h"
#include "g_levellocals.h" #include "g_levellocals.h"
@ -2478,14 +2477,7 @@ static void FS_TakeInventory (AActor *actor, const char * type, int amount)
// If it's not ammo, destroy it. Ammo needs to stick around, even // If it's not ammo, destroy it. Ammo needs to stick around, even
// when it's zero for the benefit of the weapons that use it and // when it's zero for the benefit of the weapons that use it and
// to maintain the maximum ammo amounts a backpack might have given. // to maintain the maximum ammo amounts a backpack might have given.
if (item->GetClass()->ParentClass != RUNTIME_CLASS(AAmmo)) item->DepleteOrDestroy();
{
item->Destroy ();
}
else
{
item->Amount = 0;
}
} }
} }
} }
@ -2628,7 +2620,7 @@ void FParser::SF_MaxPlayerAmmo()
if(amount < 0) amount = 0; if(amount < 0) amount = 0;
if (!iammo) if (!iammo)
{ {
iammo = static_cast<AAmmo *>(Spawn (ammotype)); iammo = static_cast<AInventory *>(Spawn (ammotype));
iammo->Amount = 0; iammo->Amount = 0;
iammo->AttachToOwner (players[playernum].mo); iammo->AttachToOwner (players[playernum].mo);
} }
@ -2644,13 +2636,13 @@ void FParser::SF_MaxPlayerAmmo()
break; break;
} }
} }
((AAmmo*)iammo)->BackpackMaxAmount=amount; iammo->IntVar("BackpackMaxAmount") = amount;
} }
t_return.type = svt_int; t_return.type = svt_int;
AInventory * iammo = players[playernum].mo->FindInventory(ammotype); AInventory * iammo = players[playernum].mo->FindInventory(ammotype);
if (iammo) t_return.value.i = iammo->MaxAmount; if (iammo) t_return.value.i = iammo->MaxAmount;
else t_return.value.i = ((AAmmo*)GetDefaultByType(ammotype))->MaxAmount; else t_return.value.i = ((AInventory*)GetDefaultByType(ammotype))->MaxAmount;
} }
} }

View file

@ -447,7 +447,7 @@ CCMD (use)
{ {
if (argv.argc() > 1 && who != NULL) if (argv.argc() > 1 && who != NULL)
{ {
SendItemUse = who->FindInventory(PClass::FindActor(argv[1])); SendItemUse = who->FindInventory(argv[1]);
} }
} }
@ -468,7 +468,7 @@ CCMD (drop)
{ {
if (argv.argc() > 1 && who != NULL) if (argv.argc() > 1 && who != NULL)
{ {
SendItemDrop = who->FindInventory(PClass::FindActor(argv[1])); SendItemDrop = who->FindInventory(argv[1]);
} }
} }
@ -513,7 +513,7 @@ CCMD (select)
{ {
if (argv.argc() > 1) if (argv.argc() > 1)
{ {
AInventory *item = who->FindInventory(PClass::FindActor(argv[1])); AInventory *item = who->FindInventory(argv[1]);
if (item != NULL) if (item != NULL)
{ {
who->InvSel = item; who->InvSel = item;

View file

@ -1,91 +0,0 @@
/*
** a_ammo.cpp
** Implements ammo and backpack items.
**
**---------------------------------------------------------------------------
** Copyright 2000-2016 Randy Heit
** Copyright 2006-2016 Cheistoph 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.
**---------------------------------------------------------------------------
**
*/
#include "c_dispatch.h"
#include "d_player.h"
#include "serializer.h"
IMPLEMENT_CLASS(AAmmo, false, false)
DEFINE_FIELD(AAmmo, BackpackAmount)
DEFINE_FIELD(AAmmo, BackpackMaxAmount)
//===========================================================================
//
// AAmmo :: Serialize
//
//===========================================================================
void AAmmo::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
auto def = (AAmmo*)GetDefault();
arc("backpackamount", BackpackAmount, def->BackpackAmount)
("backpackmaxamount", BackpackMaxAmount, def->BackpackMaxAmount);
}
//===========================================================================
//
// AAmmo :: GetParentAmmo
//
// Returns the least-derived ammo type that this ammo is a descendant of.
// That is, if this ammo is an immediate subclass of Ammo, then this ammo's
// type is returned. If this ammo's superclass is not Ammo, then this
// function travels up the inheritance chain until it finds a type that is
// an immediate subclass of Ammo and returns that.
//
// The intent of this is that all unique ammo types will be immediate
// subclasses of Ammo. To make different pickups with different ammo amounts,
// you subclass the type of ammo you want a different amount for and edit
// that.
//
//===========================================================================
PClassActor *AAmmo::GetParentAmmo () const
{
PClass *type = GetClass();
while (type->ParentClass != RUNTIME_CLASS(AAmmo) && type->ParentClass != NULL)
{
type = type->ParentClass;
}
return static_cast<PClassActor *>(type);
}
DEFINE_ACTION_FUNCTION(AAmmo, GetParentAmmo)
{
PARAM_SELF_PROLOGUE(AAmmo);
ACTION_RETURN_OBJECT(self->GetParentAmmo());
}

View file

@ -1,14 +0,0 @@
#pragma once
#include "a_pickups.h"
class AAmmo : public AInventory
{
DECLARE_CLASS (AAmmo, AInventory)
public:
virtual void Serialize(FSerializer &arc) override;
PClassActor *GetParentAmmo () const;
int BackpackAmount, BackpackMaxAmount, DropAmount;
};

View file

@ -1,644 +0,0 @@
/*
** a_armor.cpp
** Implements all variations of armor objects
**
**---------------------------------------------------------------------------
** Copyright 2002-2016 Randy Heit
** Copyright 2006-2016 Cheistoph 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.
**---------------------------------------------------------------------------
**
*/
#include <assert.h>
#include "info.h"
#include "gi.h"
#include "a_pickups.h"
#include "a_armor.h"
#include "templates.h"
#include "g_level.h"
#include "d_player.h"
#include "serializer.h"
#include "cmdlib.h"
IMPLEMENT_CLASS(AArmor, false, false)
IMPLEMENT_CLASS(ABasicArmor, false, false)
IMPLEMENT_CLASS(ABasicArmorPickup, false, false)
IMPLEMENT_CLASS(ABasicArmorBonus, false, false)
IMPLEMENT_CLASS(AHexenArmor, false, false)
//===========================================================================
//
//
// BasicArmor
//
//
//===========================================================================
DEFINE_FIELD(ABasicArmor, AbsorbCount)
DEFINE_FIELD(ABasicArmor, SavePercent)
DEFINE_FIELD(ABasicArmor, MaxAbsorb)
DEFINE_FIELD(ABasicArmor, MaxFullAbsorb)
DEFINE_FIELD(ABasicArmor, BonusCount)
DEFINE_FIELD(ABasicArmor, ArmorType)
DEFINE_FIELD(ABasicArmor, ActualSaveAmount)
//===========================================================================
//
// ABasicArmor :: Serialize
//
//===========================================================================
void ABasicArmor::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
auto def = (ABasicArmor *)GetDefault();
arc("savepercent", SavePercent, def->SavePercent)
("bonuscount", BonusCount, def->BonusCount)
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb)
("absorbcount", AbsorbCount, def->AbsorbCount)
("armortype", ArmorType, def->ArmorType)
("actualsaveamount", ActualSaveAmount, def->ActualSaveAmount);
}
//===========================================================================
//
// ABasicArmor :: Tick
//
// If BasicArmor is given to the player by means other than a
// BasicArmorPickup, then it may not have an icon set. Fix that here.
//
//===========================================================================
void ABasicArmor::Tick ()
{
Super::Tick ();
AbsorbCount = 0;
if (!Icon.isValid())
{
FString icon = gameinfo.ArmorIcon1;
if (SavePercent >= gameinfo.Armor2Percent && gameinfo.ArmorIcon2.Len() != 0)
icon = gameinfo.ArmorIcon2;
if (icon[0] != 0)
Icon = TexMan.CheckForTexture (icon, FTexture::TEX_Any);
}
}
//===========================================================================
//
// ABasicArmor :: CreateCopy
//
//===========================================================================
AInventory *ABasicArmor::CreateCopy (AActor *other)
{
// BasicArmor that is in use is stored in the inventory as BasicArmor.
// BasicArmor that is in reserve is not.
ABasicArmor *copy = Spawn<ABasicArmor> ();
copy->SavePercent = SavePercent != 0 ? SavePercent : 0.33335; // slightly more than 1/3 to avoid roundoff errors.
copy->Amount = Amount;
copy->MaxAmount = MaxAmount;
copy->Icon = Icon;
copy->BonusCount = BonusCount;
copy->ArmorType = ArmorType;
copy->ActualSaveAmount = ActualSaveAmount;
GoAwayAndDie ();
return copy;
}
//===========================================================================
//
// ABasicArmor :: HandlePickup
//
//===========================================================================
bool ABasicArmor::HandlePickup (AInventory *item)
{
if (item->GetClass() == RUNTIME_CLASS(ABasicArmor))
{
// You shouldn't be picking up BasicArmor anyway.
return true;
}
if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorBonus)) && !(item->ItemFlags & IF_IGNORESKILL))
{
ABasicArmorBonus *armor = static_cast<ABasicArmorBonus*>(item);
armor->SaveAmount = int(armor->SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
}
else if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorPickup)) && !(item->ItemFlags & IF_IGNORESKILL))
{
ABasicArmorPickup *armor = static_cast<ABasicArmorPickup*>(item);
armor->SaveAmount = int(armor->SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
}
return false;
}
//===========================================================================
//
// ABasicArmor :: AbsorbDamage
//
//===========================================================================
void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
int saved;
if (!DamageTypeDefinition::IgnoreArmor(damageType))
{
int full = MAX(0, MaxFullAbsorb - AbsorbCount);
if (damage < full)
{
saved = damage;
}
else
{
saved = full + int((damage - full) * SavePercent);
if (MaxAbsorb > 0 && saved + AbsorbCount > MaxAbsorb)
{
saved = MAX(0, MaxAbsorb - AbsorbCount);
}
}
if (Amount < saved)
{
saved = Amount;
}
newdamage -= saved;
Amount -= saved;
AbsorbCount += saved;
if (Amount == 0)
{
// The armor has become useless
SavePercent = 0;
ArmorType = NAME_None; // Not NAME_BasicArmor.
// Now see if the player has some more armor in their inventory
// and use it if so. As in Strife, the best armor is used up first.
ABasicArmorPickup *best = NULL;
AInventory *probe = Owner->Inventory;
while (probe != NULL)
{
if (probe->IsKindOf (RUNTIME_CLASS(ABasicArmorPickup)))
{
ABasicArmorPickup *inInv = static_cast<ABasicArmorPickup*>(probe);
if (best == NULL || best->SavePercent < inInv->SavePercent)
{
best = inInv;
}
}
probe = probe->Inventory;
}
if (best != NULL)
{
Owner->UseInventory (best);
}
}
damage = newdamage;
}
// Once the armor has absorbed its part of the damage, then apply its damage factor, if any, to the player
if ((damage > 0) && (ArmorType != NAME_None)) // BasicArmor is not going to have any damage factor, so skip it.
{
// This code is taken and adapted from APowerProtection::ModifyDamage().
// The differences include not using a default value, and of course the way
// the damage factor info is obtained.
// ApplyDamageFactors(ArmorType, damageType, damage, damage);
DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors;
if (df != NULL)
{
damage = newdamage = df->Apply(damageType, damage);
}
}
}
//===========================================================================
//
//
// BasicArmorPickup
//
//
//===========================================================================
DEFINE_FIELD(ABasicArmorPickup, SavePercent)
DEFINE_FIELD(ABasicArmorPickup, MaxAbsorb)
DEFINE_FIELD(ABasicArmorPickup, MaxFullAbsorb)
DEFINE_FIELD(ABasicArmorPickup, SaveAmount)
//===========================================================================
//
// ABasicArmorPickup :: Serialize
//
//===========================================================================
void ABasicArmorPickup::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
auto def = (ABasicArmorPickup *)GetDefault();
arc("savepercent", SavePercent, def->SavePercent)
("saveamount", SaveAmount, def->SaveAmount)
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb);
}
//===========================================================================
//
// ABasicArmorPickup :: CreateCopy
//
//===========================================================================
AInventory *ABasicArmorPickup::CreateCopy (AActor *other)
{
ABasicArmorPickup *copy = static_cast<ABasicArmorPickup *> (Super::CreateCopy (other));
if (!(ItemFlags & IF_IGNORESKILL))
{
SaveAmount = int(SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
}
copy->SavePercent = SavePercent;
copy->SaveAmount = SaveAmount;
copy->MaxAbsorb = MaxAbsorb;
copy->MaxFullAbsorb = MaxFullAbsorb;
return copy;
}
//===========================================================================
//
// ABasicArmorPickup :: Use
//
// Either gives you new armor or replaces the armor you already have (if
// the SaveAmount is greater than the amount of armor you own). When the
// item is auto-activated, it will only be activated if its max amount is 0
// or if you have no armor active already.
//
//===========================================================================
bool ABasicArmorPickup::Use (bool pickup)
{
ABasicArmor *armor = Owner->FindInventory<ABasicArmor> ();
if (armor == NULL)
{
armor = Spawn<ABasicArmor> ();
armor->BecomeItem ();
Owner->AddInventory (armor);
}
else
{
// If you already have more armor than this item gives you, you can't
// use it.
if (armor->Amount >= SaveAmount + armor->BonusCount)
{
return false;
}
// Don't use it if you're picking it up and already have some.
if (pickup && armor->Amount > 0 && MaxAmount > 0)
{
return false;
}
}
armor->SavePercent = SavePercent;
armor->Amount = SaveAmount + armor->BonusCount;
armor->MaxAmount = SaveAmount;
armor->Icon = Icon;
armor->MaxAbsorb = MaxAbsorb;
armor->MaxFullAbsorb = MaxFullAbsorb;
armor->ArmorType = this->GetClass()->TypeName;
armor->ActualSaveAmount = SaveAmount;
return true;
}
//===========================================================================
//
//
// BasicArmorBonus
//
//
//===========================================================================
DEFINE_FIELD(ABasicArmorBonus, SavePercent)
DEFINE_FIELD(ABasicArmorBonus, MaxSaveAmount)
DEFINE_FIELD(ABasicArmorBonus, MaxAbsorb)
DEFINE_FIELD(ABasicArmorBonus, MaxFullAbsorb)
DEFINE_FIELD(ABasicArmorBonus, SaveAmount)
DEFINE_FIELD(ABasicArmorBonus, BonusCount)
DEFINE_FIELD(ABasicArmorBonus, BonusMax)
//===========================================================================
//
// ABasicArmorBonus :: Serialize
//
//===========================================================================
void ABasicArmorBonus::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
auto def = (ABasicArmorBonus *)GetDefault();
arc("savepercent", SavePercent, def->SavePercent)
("saveamount", SaveAmount, def->SaveAmount)
("maxsaveamount", MaxSaveAmount, def->MaxSaveAmount)
("bonuscount", BonusCount, def->BonusCount)
("bonusmax", BonusMax, def->BonusMax)
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb);
}
//===========================================================================
//
// ABasicArmorBonus :: CreateCopy
//
//===========================================================================
AInventory *ABasicArmorBonus::CreateCopy (AActor *other)
{
ABasicArmorBonus *copy = static_cast<ABasicArmorBonus *> (Super::CreateCopy (other));
if (!(ItemFlags & IF_IGNORESKILL))
{
SaveAmount = int(SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
}
copy->SavePercent = SavePercent;
copy->SaveAmount = SaveAmount;
copy->MaxSaveAmount = MaxSaveAmount;
copy->BonusCount = BonusCount;
copy->BonusMax = BonusMax;
copy->MaxAbsorb = MaxAbsorb;
copy->MaxFullAbsorb = MaxFullAbsorb;
return copy;
}
//===========================================================================
//
// ABasicArmorBonus :: Use
//
// Tries to add to the amount of BasicArmor a player has.
//
//===========================================================================
bool ABasicArmorBonus::Use (bool pickup)
{
ABasicArmor *armor = Owner->FindInventory<ABasicArmor> ();
bool result = false;
if (armor == NULL)
{
armor = Spawn<ABasicArmor> ();
armor->BecomeItem ();
armor->Amount = 0;
armor->MaxAmount = MaxSaveAmount;
Owner->AddInventory (armor);
}
if (BonusCount > 0 && armor->BonusCount < BonusMax)
{
armor->BonusCount = MIN (armor->BonusCount + BonusCount, BonusMax);
result = true;
}
int saveAmount = MIN (SaveAmount, MaxSaveAmount);
if (saveAmount <= 0)
{ // If it can't give you anything, it's as good as used.
return BonusCount > 0 ? result : true;
}
// If you already have more armor than this item can give you, you can't
// use it.
if (armor->Amount >= MaxSaveAmount + armor->BonusCount)
{
return result;
}
if (armor->Amount <= 0)
{ // Should never be less than 0, but might as well check anyway
armor->Amount = 0;
armor->Icon = Icon;
armor->SavePercent = SavePercent;
armor->MaxAbsorb = MaxAbsorb;
armor->ArmorType = this->GetClass()->TypeName;
armor->MaxFullAbsorb = MaxFullAbsorb;
armor->ActualSaveAmount = MaxSaveAmount;
}
armor->Amount = MIN(armor->Amount + saveAmount, MaxSaveAmount + armor->BonusCount);
armor->MaxAmount = MAX (armor->MaxAmount, MaxSaveAmount);
return true;
}
//===========================================================================
//
//
// HexenArmor
//
//
//===========================================================================
DEFINE_FIELD(AHexenArmor, Slots)
DEFINE_FIELD(AHexenArmor, SlotsIncrement)
//===========================================================================
//
// AHexenArmor :: Serialize
//
//===========================================================================
void AHexenArmor::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
auto def = (AHexenArmor *)GetDefault();
arc.Array("slots", Slots, def->Slots, 5, true)
.Array("slotsincrement", SlotsIncrement, def->SlotsIncrement, 4);
}
//===========================================================================
//
// AHexenArmor :: CreateCopy
//
//===========================================================================
AInventory *AHexenArmor::CreateCopy (AActor *other)
{
// Like BasicArmor, HexenArmor is used in the inventory but not the map.
// health is the slot this armor occupies.
// Amount is the quantity to give (0 = normal max).
AHexenArmor *copy = Spawn<AHexenArmor> ();
copy->AddArmorToSlot (other, health, Amount);
GoAwayAndDie ();
return copy;
}
//===========================================================================
//
// AHexenArmor :: CreateTossable
//
// Since this isn't really a single item, you can't drop it. Ever.
//
//===========================================================================
AInventory *AHexenArmor::CreateTossable ()
{
return NULL;
}
//===========================================================================
//
// AHexenArmor :: HandlePickup
//
//===========================================================================
bool AHexenArmor::HandlePickup (AInventory *item)
{
if (item->IsKindOf (RUNTIME_CLASS(AHexenArmor)))
{
if (AddArmorToSlot (Owner, item->health, item->Amount))
{
item->ItemFlags |= IF_PICKUPGOOD;
}
return true;
}
return false;
}
//===========================================================================
//
// AHexenArmor :: AddArmorToSlot
//
//===========================================================================
bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount)
{
APlayerPawn *ppawn;
double hits;
if (actor->player != NULL)
{
ppawn = static_cast<APlayerPawn *>(actor);
}
else
{
ppawn = NULL;
}
if (slot < 0 || slot > 3)
{
return false;
}
if (amount <= 0)
{
hits = SlotsIncrement[slot];
if (Slots[slot] < hits)
{
Slots[slot] = hits;
return true;
}
}
else
{
hits = amount * 5;
auto total = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
auto max = SlotsIncrement[0] + SlotsIncrement[1] + SlotsIncrement[2] + SlotsIncrement[3] + Slots[4] + 4 * 5;
if (total < max)
{
Slots[slot] += hits;
return true;
}
}
return false;
}
//===========================================================================
//
// AHexenArmor :: AbsorbDamage
//
//===========================================================================
void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
if (!DamageTypeDefinition::IgnoreArmor(damageType))
{
double savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
if (savedPercent)
{ // armor absorbed some damage
if (savedPercent > 100)
{
savedPercent = 100;
}
for (int i = 0; i < 4; i++)
{
if (Slots[i])
{
// 300 damage always wipes out the armor unless some was added
// with the dragon skin bracers.
if (damage < 10000)
{
Slots[i] -= damage * SlotsIncrement[i] / 300.;
if (Slots[i] < 2)
{
Slots[i] = 0;
}
}
else
{
Slots[i] = 0;
}
}
}
int saved = int(damage * savedPercent / 100.);
if (saved > savedPercent*2)
{
saved = int(savedPercent*2);
}
newdamage -= saved;
damage = newdamage;
}
}
}
//===========================================================================
//
// AHexenArmor :: DepleteOrDestroy
//
//===========================================================================
void AHexenArmor::DepleteOrDestroy()
{
for (int i = 0; i < 4; i++)
{
Slots[i] = 0;
}
}

View file

@ -1,89 +0,0 @@
#pragma once
#include "a_pickups.h"
// Armor absorbs some damage for the player.
class AArmor : public AInventory
{
DECLARE_CLASS (AArmor, AInventory)
};
// Basic armor absorbs a specific percent of the damage. You should
// never pickup a BasicArmor. Instead, you pickup a BasicArmorPickup
// or BasicArmorBonus and those gives you BasicArmor when it activates.
class ABasicArmor : public AArmor
{
DECLARE_CLASS (ABasicArmor, AArmor)
public:
virtual void Serialize(FSerializer &arc) override;
virtual void Tick () override;
virtual AInventory *CreateCopy (AActor *other) override;
virtual bool HandlePickup (AInventory *item) override;
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
int AbsorbCount;
double SavePercent;
int MaxAbsorb;
int MaxFullAbsorb;
int BonusCount;
FNameNoInit ArmorType;
int ActualSaveAmount;
};
// BasicArmorPickup replaces the armor you have.
class ABasicArmorPickup : public AArmor
{
DECLARE_CLASS (ABasicArmorPickup, AArmor)
public:
virtual void Serialize(FSerializer &arc) override;
virtual AInventory *CreateCopy (AActor *other) override;
virtual bool Use (bool pickup) override;
double SavePercent;
int MaxAbsorb;
int MaxFullAbsorb;
int SaveAmount;
};
// BasicArmorBonus adds to the armor you have.
class ABasicArmorBonus : public AArmor
{
DECLARE_CLASS (ABasicArmorBonus, AArmor)
public:
virtual void Serialize(FSerializer &arc) override;
virtual AInventory *CreateCopy (AActor *other) override;
virtual bool Use (bool pickup) override;
double SavePercent; // The default, for when you don't already have armor
int MaxSaveAmount;
int MaxAbsorb;
int MaxFullAbsorb;
int SaveAmount;
int BonusCount;
int BonusMax;
};
// Hexen armor consists of four separate armor types plus a conceptual armor
// type (the player himself) that work together as a single armor.
class AHexenArmor : public AArmor
{
DECLARE_CLASS (AHexenArmor, AArmor)
public:
virtual void Serialize(FSerializer &arc) override;
virtual AInventory *CreateCopy (AActor *other) override;
virtual AInventory *CreateTossable () override;
virtual bool HandlePickup (AInventory *item) override;
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
virtual void DepleteOrDestroy() override;
double Slots[5];
double SlotsIncrement[4];
protected:
bool AddArmorToSlot (AActor *actor, int slot, int amount);
};

View file

@ -51,7 +51,6 @@
// //
//=========================================================================== //===========================================================================
//=========================================================================== //===========================================================================
// //
// //
@ -63,14 +62,10 @@ struct OneKey
int count; int count;
bool check(AActor *owner) bool check(AActor *owner)
{
if (owner->IsKindOf(RUNTIME_CLASS(AKey)))
{ {
// P_GetMapColorForKey() checks the key directly // P_GetMapColorForKey() checks the key directly
return owner->IsA(key) || owner->GetSpecies() == key->TypeName; if (owner->IsA(key) || owner->GetSpecies() == key->TypeName) return true;
}
else
{
// Other calls check an actor that may have a key in its inventory. // Other calls check an actor that may have a key in its inventory.
AInventory *item; AInventory *item;
@ -87,7 +82,6 @@ struct OneKey
} }
return false; return false;
} }
}
}; };
//=========================================================================== //===========================================================================
@ -138,9 +132,10 @@ struct Lock
// An empty key list means that any key will do // An empty key list means that any key will do
if (!keylist.Size()) if (!keylist.Size())
{ {
auto kt = PClass::FindActor(NAME_Key);
for (AInventory * item = owner->Inventory; item != NULL; item = item->Inventory) for (AInventory * item = owner->Inventory; item != NULL; item = item->Inventory)
{ {
if (item->IsKindOf (RUNTIME_CLASS(AKey))) if (item->IsKindOf (kt))
{ {
return true; return true;
} }
@ -192,12 +187,12 @@ static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc)
keygroup->anykeylist.Push (k); keygroup->anykeylist.Push (k);
//... but only keys get key numbers! //... but only keys get key numbers!
if (mi->IsDescendantOf(RUNTIME_CLASS(AKey))) if (mi->IsDescendantOf(PClass::FindActor(NAME_Key)))
{ {
if (!ignorekey && if (!ignorekey &&
static_cast<AKey*>(GetDefaultByType(mi))->KeyNumber == 0) GetDefaultByType(mi)->special1 == 0)
{ {
static_cast<AKey*>(GetDefaultByType(mi))->KeyNumber=++currentnumber; GetDefaultByType(mi)->special1 = ++currentnumber;
} }
} }
} }
@ -387,14 +382,15 @@ static void ParseLock(FScanner &sc)
static void ClearLocks() static void ClearLocks()
{ {
unsigned int i; unsigned int i;
auto kt = PClass::FindActor(NAME_Key);
for(i = 0; i < PClassActor::AllActorClasses.Size(); i++) for(i = 0; i < PClassActor::AllActorClasses.Size(); i++)
{ {
if (PClassActor::AllActorClasses[i]->IsDescendantOf(RUNTIME_CLASS(AKey))) if (PClassActor::AllActorClasses[i]->IsDescendantOf(kt))
{ {
AKey *key = static_cast<AKey*>(GetDefaultByType(PClassActor::AllActorClasses[i])); auto key = GetDefaultByType(PClassActor::AllActorClasses[i]);
if (key != NULL) if (key != NULL)
{ {
key->KeyNumber = 0; key->special1 = 0;
} }
} }
} }
@ -523,15 +519,6 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote)
return false; return false;
} }
//==========================================================================
//
// AKey implementation
//
//==========================================================================
IMPLEMENT_CLASS(AKey, false, false)
DEFINE_FIELD(AKey, KeyNumber)
//========================================================================== //==========================================================================
// //
// These functions can be used to get color information for // These functions can be used to get color information for

View file

@ -1,14 +1,8 @@
#ifndef A_KEYS_H #ifndef A_KEYS_H
#define A_KEYS_H #define A_KEYS_H
#include "a_pickups.h" class AActor;
class AInventory;
class AKey : public AInventory
{
DECLARE_CLASS (AKey, AInventory)
public:
BYTE KeyNumber;
};
bool P_CheckKeys (AActor *owner, int keynum, bool remote); bool P_CheckKeys (AActor *owner, int keynum, bool remote);
void P_InitKeyMessages (); void P_InitKeyMessages ();

View file

@ -20,7 +20,6 @@
#include "p_spec.h" #include "p_spec.h"
#include "serializer.h" #include "serializer.h"
#include "virtual.h" #include "virtual.h"
#include "a_ammo.h"
#include "c_functions.h" #include "c_functions.h"
#include "g_levellocals.h" #include "g_levellocals.h"
@ -80,71 +79,6 @@ void PClassInventory::Finalize(FStateDefinitions &statedef)
((AActor*)Defaults)->flags |= MF_SPECIAL; ((AActor*)Defaults)->flags |= MF_SPECIAL;
} }
//---------------------------------------------------------------------------
//
// PROC A_RestoreSpecialThing1
//
// Make a special thing visible again.
//
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialThing1)
{
PARAM_SELF_PROLOGUE(AInventory);
self->renderflags &= ~RF_INVISIBLE;
if (self->DoRespawn ())
{
S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE);
}
return 0;
}
//---------------------------------------------------------------------------
//
// PROC A_RestoreSpecialThing2
//
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialThing2)
{
PARAM_SELF_PROLOGUE(AInventory);
self->flags |= MF_SPECIAL;
if (!(self->GetDefault()->flags & MF_NOGRAVITY))
{
self->flags &= ~MF_NOGRAVITY;
}
self->SetState (self->SpawnState);
return 0;
}
//---------------------------------------------------------------------------
//
// PROC A_RestoreSpecialDoomThing
//
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialDoomThing)
{
PARAM_SELF_PROLOGUE(AInventory);
self->renderflags &= ~RF_INVISIBLE;
self->flags |= MF_SPECIAL;
if (!(self->GetDefault()->flags & MF_NOGRAVITY))
{
self->flags &= ~MF_NOGRAVITY;
}
if (self->DoRespawn ())
{
self->SetState (self->SpawnState);
S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE);
Spawn ("ItemFog", self->Pos(), ALLOW_REPLACE);
}
return 0;
}
int AInventory::StaticLastMessageTic; int AInventory::StaticLastMessageTic;
FString AInventory::StaticLastMessage; FString AInventory::StaticLastMessage;
@ -908,7 +842,7 @@ void AInventory::Touch (AActor *toucher)
// real player to make noise. // real player to make noise.
if (player != NULL) if (player != NULL)
{ {
PlayPickupSound (player->mo); CallPlayPickupSound (player->mo);
if (!(ItemFlags & IF_NOSCREENFLASH)) if (!(ItemFlags & IF_NOSCREENFLASH))
{ {
player->bonuscount = BONUSADD; player->bonuscount = BONUSADD;
@ -916,7 +850,7 @@ void AInventory::Touch (AActor *toucher)
} }
else else
{ {
PlayPickupSound (toucher); CallPlayPickupSound (toucher);
} }
} }
@ -1117,19 +1051,10 @@ void AInventory::OnDestroy ()
void AInventory::DepleteOrDestroy () void AInventory::DepleteOrDestroy ()
{ {
// If it's not ammo or an internal armor, destroy it. IFVIRTUAL(AInventory, DepleteOrDestroy)
// Ammo needs to stick around, even when it's zero for the benefit
// of the weapons that use it and to maintain the maximum ammo
// amounts a backpack might have given.
// Armor shouldn't be removed because they only work properly when
// they are the last items in the inventory.
if (ItemFlags & IF_KEEPDEPLETED)
{ {
Amount = 0; VMValue params[1] = { (DObject*)this };
} GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
else
{
Destroy();
} }
} }
@ -1273,6 +1198,11 @@ bool AInventory::DoRespawn ()
return true; return true;
} }
DEFINE_ACTION_FUNCTION(AInventory, DoRespawn)
{
PARAM_SELF_PROLOGUE(AInventory);
ACTION_RETURN_BOOL(self->DoRespawn());
}
//=========================================================================== //===========================================================================
// //
@ -1314,29 +1244,7 @@ bool AInventory::TryPickup (AActor *&toucher)
ItemFlags &= ~IF_PICKUPGOOD; ItemFlags &= ~IF_PICKUPGOOD;
GoAwayAndDie (); GoAwayAndDie ();
} }
else if (MaxAmount == 0 && !IsKindOf(RUNTIME_CLASS(AAmmo))) else if (MaxAmount > 0)
{
// Special case: If an item's MaxAmount is 0, you can still pick it
// up if it is autoactivate-able.
if (!(ItemFlags & IF_AUTOACTIVATE))
{
return false;
}
// The item is placed in the inventory just long enough to be used.
toucher->AddInventory (this);
bool usegood = CallUse (true);
toucher->RemoveInventory (this);
if (usegood)
{
GoAwayAndDie ();
}
else
{
return false;
}
}
else
{ {
// Add the item to the inventory. It is not already there, or HandlePickup // Add the item to the inventory. It is not already there, or HandlePickup
// would have already taken care of it. // would have already taken care of it.
@ -1374,6 +1282,25 @@ bool AInventory::TryPickup (AActor *&toucher)
} }
} }
} }
else if (ItemFlags & IF_AUTOACTIVATE)
{
// Special case: If an item's MaxAmount is 0, you can still pick it
// up if it is autoactivate-able.
// The item is placed in the inventory just long enough to be used.
toucher->AddInventory(this);
bool usegood = CallUse(true);
toucher->RemoveInventory(this);
if (usegood)
{
GoAwayAndDie();
}
else
{
return false;
}
}
return true; return true;
} }

View file

@ -82,7 +82,7 @@ public:
// virtual methods that only get overridden by special internal classes, like DehackedPickup. // virtual methods that only get overridden by special internal classes, like DehackedPickup.
// There is no need to expose these to scripts. // There is no need to expose these to scripts.
virtual void DepleteOrDestroy (); void DepleteOrDestroy ();
virtual bool ShouldRespawn (); virtual bool ShouldRespawn ();
virtual void DoPickupSpecial (AActor *toucher); virtual void DoPickupSpecial (AActor *toucher);

View file

@ -1,258 +0,0 @@
/*
** a_weaponpieces.cpp
** Implements generic weapon pieces
**
**---------------------------------------------------------------------------
** Copyright 2006-2016 Cheistoph Oelckers
** Copyright 2006-2016 Randy Heit
** 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.
**---------------------------------------------------------------------------
**
*/
#include "a_pickups.h"
#include "a_weaponpiece.h"
#include "doomstat.h"
#include "serializer.h"
IMPLEMENT_CLASS(AWeaponHolder, false, false)
DEFINE_FIELD(AWeaponHolder, PieceMask);
DEFINE_FIELD(AWeaponHolder, PieceWeapon);
//===========================================================================
//
//
//
//===========================================================================
void AWeaponHolder::Serialize(FSerializer &arc)
{
Super::Serialize(arc);
arc("piecemask", PieceMask)
("pieceweapon", PieceWeapon);
}
IMPLEMENT_CLASS(AWeaponPiece, false, true)
IMPLEMENT_POINTERS_START(AWeaponPiece)
IMPLEMENT_POINTER(FullWeapon)
IMPLEMENT_POINTER(WeaponClass)
IMPLEMENT_POINTERS_END
//===========================================================================
//
//
//
//===========================================================================
void AWeaponPiece::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
auto def = (AWeaponPiece*)GetDefault();
arc("weaponclass", WeaponClass, def->WeaponClass)
("fullweapon", FullWeapon)
("piecevalue", PieceValue, def->PieceValue);
}
//==========================================================================
//
// TryPickupWeaponPiece
//
//==========================================================================
bool AWeaponPiece::TryPickupRestricted (AActor *&toucher)
{
// Wrong class, but try to pick up for ammo
if (CallShouldStay())
{ // Can't pick up weapons for other classes in coop netplay
return false;
}
AWeapon * Defaults=(AWeapon*)GetDefaultByType(WeaponClass);
bool gaveSome = !!(toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1) +
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2));
if (gaveSome)
{
GoAwayAndDie ();
}
return gaveSome;
}
//==========================================================================
//
// TryPickupWeaponPiece
//
//==========================================================================
bool AWeaponPiece::TryPickup (AActor *&toucher)
{
AInventory * inv;
AWeaponHolder * hold=NULL;
bool shouldStay = PrivateShouldStay ();
int gaveAmmo;
AWeapon * Defaults=(AWeapon*)GetDefaultByType(WeaponClass);
FullWeapon=NULL;
for(inv=toucher->Inventory;inv;inv=inv->Inventory)
{
if (inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder)))
{
hold=static_cast<AWeaponHolder*>(inv);
if (hold->PieceWeapon==WeaponClass) break;
hold=NULL;
}
}
if (!hold)
{
hold=static_cast<AWeaponHolder*>(Spawn(RUNTIME_CLASS(AWeaponHolder)));
hold->BecomeItem();
hold->AttachToOwner(toucher);
hold->PieceMask=0;
hold->PieceWeapon=WeaponClass;
}
if (shouldStay)
{
// Cooperative net-game
if (hold->PieceMask & PieceValue)
{
// Already has the piece
return false;
}
toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1);
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2);
}
else
{ // Deathmatch or singleplayer game
gaveAmmo = toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1) +
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2);
if (hold->PieceMask & PieceValue)
{
// Already has the piece, check if mana needed
if (!gaveAmmo) return false;
GoAwayAndDie();
return true;
}
}
hold->PieceMask |= PieceValue;
// Check if weapon assembled
if (hold->PieceMask== (1<<Defaults->health)-1)
{
if (!toucher->FindInventory (WeaponClass))
{
FullWeapon= static_cast<AWeapon*>(Spawn(WeaponClass));
// The weapon itself should not give more ammo to the player!
FullWeapon->AmmoGive1=0;
FullWeapon->AmmoGive2=0;
FullWeapon->AttachToOwner(toucher);
FullWeapon->AmmoGive1=Defaults->AmmoGive1;
FullWeapon->AmmoGive2=Defaults->AmmoGive2;
}
}
GoAwayAndDie();
return true;
}
//===========================================================================
//
//
//
//===========================================================================
bool AWeaponPiece::ShouldStay ()
{
return PrivateShouldStay ();
}
//===========================================================================
//
//
//
//===========================================================================
bool AWeaponPiece::PrivateShouldStay ()
{
// We want a weapon piece to behave like a weapon, so follow the exact
// same logic as weapons when deciding whether or not to stay.
if (((multiplayer &&
(!deathmatch && !alwaysapplydmflags)) || (dmflags & DF_WEAPONS_STAY)) &&
!(flags&MF_DROPPED))
{
return true;
}
return false;
}
//===========================================================================
//
// PickupMessage
//
// Returns the message to print when this actor is picked up.
//
//===========================================================================
FString AWeaponPiece::PickupMessage ()
{
if (FullWeapon)
{
return FullWeapon->PickupMessage();
}
else
{
return Super::PickupMessage();
}
}
//===========================================================================
//
// DoPlayPickupSound
//
// Plays a sound when this actor is picked up.
//
//===========================================================================
void AWeaponPiece::PlayPickupSound (AActor *toucher)
{
if (FullWeapon)
{
FullWeapon->PlayPickupSound(toucher);
}
else
{
Super::PlayPickupSound(toucher);
}
}

View file

@ -1,37 +0,0 @@
#pragma once
#include "a_pickups.h"
#include "a_weapons.h"
class AWeaponPiece : public AInventory
{
DECLARE_CLASS (AWeaponPiece, AInventory)
HAS_OBJECT_POINTERS
protected:
bool PrivateShouldStay ();
public:
virtual void Serialize(FSerializer &arc) override;
virtual bool TryPickup (AActor *&toucher) override;
virtual bool TryPickupRestricted (AActor *&toucher) override;
virtual bool ShouldStay () override;
virtual FString PickupMessage () override;
virtual void PlayPickupSound (AActor *toucher) override;
int PieceValue;
PClassActor *WeaponClass;
TObjPtr<AWeapon> FullWeapon;
};
// an internal class to hold the information for player class independent weapon piece handling
// [BL] Needs to be available for SBarInfo to check weaponpieces
class AWeaponHolder : public AInventory
{
DECLARE_CLASS (AWeaponHolder, AInventory)
public:
int PieceMask;
PClassActor * PieceWeapon;
virtual void Serialize(FSerializer &arc) override;
};

View file

@ -54,7 +54,7 @@
#include "serializer.h" #include "serializer.h"
#include "thingdef.h" #include "thingdef.h"
#include "virtual.h" #include "virtual.h"
#include "a_ammo.h"
#define BONUSADD 6 #define BONUSADD 6
@ -499,9 +499,9 @@ void AWeapon::AttachToOwner (AActor *other)
// //
//=========================================================================== //===========================================================================
AAmmo *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount) AInventory *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount)
{ {
AAmmo *ammo; AInventory *ammo;
if (ammotype == NULL) if (ammotype == NULL)
{ {
@ -518,10 +518,10 @@ AAmmo *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount)
{ {
amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor));
} }
ammo = static_cast<AAmmo *>(other->FindInventory (ammotype)); ammo = other->FindInventory (ammotype);
if (ammo == NULL) if (ammo == NULL)
{ {
ammo = static_cast<AAmmo *>(Spawn (ammotype)); ammo = static_cast<AInventory *>(Spawn (ammotype));
ammo->Amount = MIN (amount, ammo->MaxAmount); ammo->Amount = MIN (amount, ammo->MaxAmount);
ammo->AttachToOwner (other); ammo->AttachToOwner (other);
} }
@ -545,7 +545,7 @@ AAmmo *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount)
//=========================================================================== //===========================================================================
EXTERN_CVAR(Bool, sv_unlimited_pickup) EXTERN_CVAR(Bool, sv_unlimited_pickup)
bool AWeapon::AddExistingAmmo (AAmmo *ammo, int amount) bool AWeapon::AddExistingAmmo (AInventory *ammo, int amount)
{ {
if (ammo != NULL && (ammo->Amount < ammo->MaxAmount || sv_unlimited_pickup)) if (ammo != NULL && (ammo->Amount < ammo->MaxAmount || sv_unlimited_pickup))
{ {

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "a_ammo.h" #include "a_pickups.h"
class PClassWeapon; class PClassWeapon;
class AWeapon; class AWeapon;
@ -126,7 +125,7 @@ public:
float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction.
// In-inventory instance variables // In-inventory instance variables
TObjPtr<AAmmo> Ammo1, Ammo2; TObjPtr<AInventory> Ammo1, Ammo2;
TObjPtr<AWeapon> SisterWeapon; TObjPtr<AWeapon> SisterWeapon;
float FOVScale; float FOVScale;
int Crosshair; // 0 to use player's crosshair int Crosshair; // 0 to use player's crosshair
@ -182,8 +181,8 @@ public:
}; };
protected: protected:
AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount); AInventory *AddAmmo (AActor *other, PClassActor *ammotype, int amount);
bool AddExistingAmmo (AAmmo *ammo, int amount); bool AddExistingAmmo (AInventory *ammo, int amount);
AWeapon *AddWeapon (PClassWeapon *weapon); AWeapon *AddWeapon (PClassWeapon *weapon);
}; };

View file

@ -13,7 +13,6 @@
#include "serializer.h" #include "serializer.h"
#include "p_enemy.h" #include "p_enemy.h"
#include "d_player.h" #include "d_player.h"
#include "a_armor.h"
#include "r_data/sprites.h" #include "r_data/sprites.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "virtual.h" #include "virtual.h"
@ -137,7 +136,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
for (item = morphed->Inventory; item != nullptr; ) for (item = morphed->Inventory; item != nullptr; )
{ {
AInventory *next = item->Inventory; AInventory *next = item->Inventory;
if (item->IsKindOf (RUNTIME_CLASS(AArmor))) if (item->IsKindOf (PClass::FindActor(NAME_Armor)))
{ {
item->DepleteOrDestroy(); item->DepleteOrDestroy();
} }
@ -364,10 +363,11 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
} }
pmo->Destroy (); pmo->Destroy ();
// Restore playerclass armor to its normal amount. // Restore playerclass armor to its normal amount.
AHexenArmor *hxarmor = mo->FindInventory<AHexenArmor>(); auto hxarmor = mo->FindInventory(NAME_HexenArmor);
if (hxarmor != nullptr) if (hxarmor != nullptr)
{ {
hxarmor->Slots[4] = mo->GetClass()->HexenArmor[0]; double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr);
Slots[4] = mo->GetClass()->HexenArmor[0];
} }
return true; return true;
} }

View file

@ -294,7 +294,6 @@ int FindMugShotStateIndex(FName state);
// Base Status Bar ---------------------------------------------------------- // Base Status Bar ----------------------------------------------------------
class FTexture; class FTexture;
class AAmmo;
enum enum
{ {
@ -395,7 +394,7 @@ protected:
void RefreshBackground () const; void RefreshBackground () const;
void GetCurrentAmmo (AAmmo *&ammo1, AAmmo *&ammo2, int &ammocount1, int &ammocount2) const; void GetCurrentAmmo (AInventory *&ammo1, AInventory *&ammo2, int &ammocount1, int &ammocount2) const;
public: public:
AInventory *ValidateInvFirst (int numVisible) const; AInventory *ValidateInvFirst (int numVisible) const;

View file

@ -45,20 +45,17 @@
#include "st_stuff.h" #include "st_stuff.h"
#include "m_swap.h" #include "m_swap.h"
#include "a_keys.h" #include "a_keys.h"
#include "a_armor.h"
#include "templates.h" #include "templates.h"
#include "i_system.h" #include "i_system.h"
#include "sbarinfo.h" #include "sbarinfo.h"
#include "gi.h" #include "gi.h"
#include "r_data/r_translate.h" #include "r_data/r_translate.h"
#include "a_weaponpiece.h"
#include "g_level.h" #include "g_level.h"
#include "v_palette.h" #include "v_palette.h"
#include "p_acs.h" #include "p_acs.h"
#include "gstrings.h" #include "gstrings.h"
#include "version.h" #include "version.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "a_ammo.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#define ARTIFLASH_OFFSET (statusBar->invBarOffset+6) #define ARTIFLASH_OFFSET (statusBar->invBarOffset+6)
@ -1069,7 +1066,7 @@ public:
//prepare ammo counts //prepare ammo counts
GetCurrentAmmo(ammo1, ammo2, ammocount1, ammocount2); GetCurrentAmmo(ammo1, ammo2, ammocount1, ammocount2);
armor = CPlayer->mo->FindInventory<ABasicArmor>(); armor = CPlayer->mo->FindInventory(NAME_BasicArmor);
if(state != HUD_AltHud) if(state != HUD_AltHud)
{ {
@ -1517,9 +1514,9 @@ public:
return translationtables[TRANSLATION_Players][int(CPlayer - players)]; return translationtables[TRANSLATION_Players][int(CPlayer - players)];
} }
AAmmo *ammo1, *ammo2; AInventory *ammo1, *ammo2;
int ammocount1, ammocount2; int ammocount1, ammocount2;
ABasicArmor *armor; AInventory *armor;
FImageCollection Images; FImageCollection Images;
unsigned int invBarOffset; unsigned int invBarOffset;

View file

@ -244,31 +244,31 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
texture = TexMan(statusBar->CPlayer->mo->ScoreIcon); texture = TexMan(statusBar->CPlayer->mo->ScoreIcon);
else if(type == AMMO1) else if(type == AMMO1)
{ {
AAmmo *ammo = statusBar->ammo1; auto ammo = statusBar->ammo1;
if(ammo != NULL) if(ammo != NULL)
GetIcon(ammo); GetIcon(ammo);
} }
else if(type == AMMO2) else if(type == AMMO2)
{ {
AAmmo *ammo = statusBar->ammo2; auto ammo = statusBar->ammo2;
if(ammo != NULL) if(ammo != NULL)
GetIcon(ammo); GetIcon(ammo);
} }
else if(type == ARMOR) else if(type == ARMOR)
{ {
ABasicArmor *armor = statusBar->armor; auto armor = statusBar->armor;
if(armor != NULL && armor->Amount != 0) if(armor != NULL && armor->Amount != 0)
GetIcon(armor); GetIcon(armor);
} }
else if(type == WEAPONICON) else if(type == WEAPONICON)
{ {
AWeapon *weapon = statusBar->CPlayer->ReadyWeapon; auto weapon = statusBar->CPlayer->ReadyWeapon;
if(weapon != NULL) if(weapon != NULL)
GetIcon(weapon); GetIcon(weapon);
} }
else if(type == SIGIL) else if(type == SIGIL)
{ {
AInventory *item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil)); auto item = statusBar->CPlayer->mo->FindInventory(NAME_Sigil);
if (item != NULL) if (item != NULL)
texture = TexMan(item->Icon); texture = TexMan(item->Icon);
} }
@ -276,13 +276,15 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
{ {
int armorType = type - HEXENARMOR_ARMOR; int armorType = type - HEXENARMOR_ARMOR;
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>(); auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor);
if (harmor != NULL) if (harmor != NULL)
{ {
if (harmor->Slots[armorType] > 0 && harmor->SlotsIncrement[armorType] > 0) double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr);
if (Slots[armorType] > 0 && SlotsIncrement[armorType] > 0)
{ {
//combine the alpha values //combine the alpha values
alpha *= MIN(1., harmor->Slots[armorType] / harmor->SlotsIncrement[armorType]); alpha *= MIN(1., Slots[armorType] / SlotsIncrement[armorType]);
texture = statusBar->Images[image]; texture = statusBar->Images[image];
} }
else else
@ -416,10 +418,10 @@ class CommandDrawSwitchableImage : public CommandDrawImage
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{ {
PClassActor *cls = PClassActor::AllActorClasses[i]; PClassActor *cls = PClassActor::AllActorClasses[i];
if (cls->IsDescendantOf(RUNTIME_CLASS(AKey))) if (cls->IsDescendantOf(PClass::FindActor(NAME_Key)))
{ {
AKey *key = (AKey *)GetDefaultByType(cls); auto key = GetDefaultByType(cls);
if (key->KeyNumber == keynum) if (key->special1 == keynum)
return cls->TypeName; return cls->TypeName;
} }
} }
@ -554,9 +556,9 @@ class CommandDrawSwitchableImage : public CommandDrawImage
for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory)
{ {
if(item->IsKindOf(RUNTIME_CLASS(AKey))) if(item->IsKindOf(PClass::FindActor(NAME_Key)))
{ {
int keynum = static_cast<AKey *>(item)->KeyNumber; int keynum = item->special1;
if(keynum) if(keynum)
{ {
if(keynum == conditionalValue[0]) if(keynum == conditionalValue[0])
@ -592,11 +594,11 @@ class CommandDrawSwitchableImage : public CommandDrawImage
} }
else if(condition == ARMORTYPE) else if(condition == ARMORTYPE)
{ {
ABasicArmor *armor = (ABasicArmor *) statusBar->CPlayer->mo->FindInventory(NAME_BasicArmor); auto armor = statusBar->CPlayer->mo->FindInventory(NAME_BasicArmor);
if(armor != NULL) if(armor != NULL)
{ {
bool matches1 = armor->ArmorType.GetIndex() == armorType[0] && EvaluateOperation(conditionalOperator[0], conditionalValue[0], armor->Amount); bool matches1 = armor->NameVar(NAME_ArmorType).GetIndex() == armorType[0] && EvaluateOperation(conditionalOperator[0], conditionalValue[0], armor->Amount);
bool matches2 = armor->ArmorType.GetIndex() == armorType[1] && EvaluateOperation(conditionalOperator[1], conditionalValue[1], armor->Amount); bool matches2 = armor->NameVar(NAME_ArmorType).GetIndex() == armorType[1] && EvaluateOperation(conditionalOperator[1], conditionalValue[1], armor->Amount);
drawAlt = 1; drawAlt = 1;
if(conditionAnd) if(conditionAnd)
@ -614,12 +616,12 @@ class CommandDrawSwitchableImage : public CommandDrawImage
} }
else //check the inventory items and draw selected sprite else //check the inventory items and draw selected sprite
{ {
AInventory* item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(inventoryItem[0])); AInventory* item = statusBar->CPlayer->mo->FindInventory(inventoryItem[0]);
if(item == NULL || !EvaluateOperation(conditionalOperator[0], conditionalValue[0], item->Amount)) if(item == NULL || !EvaluateOperation(conditionalOperator[0], conditionalValue[0], item->Amount))
drawAlt = 1; drawAlt = 1;
if(conditionAnd) if(conditionAnd)
{ {
item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(inventoryItem[1])); item = statusBar->CPlayer->mo->FindInventory(inventoryItem[1]);
bool secondCondition = item != NULL && EvaluateOperation(conditionalOperator[1], conditionalValue[1], item->Amount); bool secondCondition = item != NULL && EvaluateOperation(conditionalOperator[1], conditionalValue[1], item->Amount);
if((item != NULL && secondCondition) && drawAlt == 0) //both if((item != NULL && secondCondition) && drawAlt == 0) //both
{ {
@ -1076,10 +1078,10 @@ class CommandDrawNumber : public CommandDrawString
if(!parenthesized || !sc.CheckToken(TK_StringConst)) if(!parenthesized || !sc.CheckToken(TK_StringConst))
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
inventoryItem = PClass::FindActor(sc.String); inventoryItem = PClass::FindActor(sc.String);
if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
{ {
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
inventoryItem = RUNTIME_CLASS(AAmmo); inventoryItem = PClass::FindActor(NAME_Ammo);
} }
if(parenthesized) sc.MustGetToken(')'); if(parenthesized) sc.MustGetToken(')');
@ -1092,10 +1094,10 @@ class CommandDrawNumber : public CommandDrawString
if(!parenthesized || !sc.CheckToken(TK_StringConst)) if(!parenthesized || !sc.CheckToken(TK_StringConst))
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
inventoryItem = PClass::FindActor(sc.String); inventoryItem = PClass::FindActor(sc.String);
if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
{ {
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
inventoryItem = RUNTIME_CLASS(AAmmo); inventoryItem = PClass::FindActor(NAME_Ammo);
} }
if(parenthesized) sc.MustGetToken(')'); if(parenthesized) sc.MustGetToken(')');
@ -1409,16 +1411,16 @@ class CommandDrawNumber : public CommandDrawString
case SAVEPERCENT: case SAVEPERCENT:
{ {
double add = 0; double add = 0;
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>(); auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor);
if(harmor != NULL) if(harmor != NULL)
{ {
add = harmor->Slots[0] + harmor->Slots[1] + double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]; add = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
} }
//Hexen counts basic armor also so we should too. //Hexen counts basic armor also so we should too.
if(statusBar->armor != NULL) if(statusBar->armor != NULL)
{ {
add += statusBar->armor->SavePercent * 100; add += statusBar->armor->FloatVar(NAME_SavePercent) * 100;
} }
if(value == ARMORCLASS) if(value == ARMORCLASS)
add /= 5; add /= 5;
@ -1435,7 +1437,7 @@ class CommandDrawNumber : public CommandDrawString
{ {
// num = statusBar.CPlayer.mo.GetEffectTicsForItem(inventoryItem) / TICRATE + 1; // num = statusBar.CPlayer.mo.GetEffectTicsForItem(inventoryItem) / TICRATE + 1;
static VMFunction *func = nullptr; static VMFunction *func = nullptr;
if (func == nullptr) func = static_cast<PFunction*>(RUNTIME_CLASS(APlayerPawn)->Symbols.FindSymbol("GetEffectTicsForItem", false))->Variants[0].Implementation; if (func == nullptr) func = PClass::FindFunction(NAME_PlayerPawn, "GetEffectTicsForItem");
VMValue params[] = { statusBar->CPlayer->mo, inventoryItem }; VMValue params[] = { statusBar->CPlayer->mo, inventoryItem };
int retv; int retv;
VMReturn ret(&retv); VMReturn ret(&retv);
@ -1474,7 +1476,7 @@ class CommandDrawNumber : public CommandDrawString
num = 0; num = 0;
for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory)
{ {
if(item->IsKindOf(RUNTIME_CLASS(AKey))) if(item->IsKindOf(PClass::FindActor(NAME_Key)))
num++; num++;
} }
break; break;
@ -2429,7 +2431,7 @@ class CommandDrawKeyBar : public SBarInfoCommand
int rowWidth = 0; int rowWidth = 0;
for(unsigned int i = 0;i < number+keyOffset;i++) for(unsigned int i = 0;i < number+keyOffset;i++)
{ {
while(!item->Icon.isValid() || !item->IsKindOf(RUNTIME_CLASS(AKey))) while(!item->Icon.isValid() || !item->IsKindOf(PClass::FindActor(NAME_Key)))
{ {
item = item->Inventory; item = item->Inventory;
if(item == NULL) if(item == NULL)
@ -2630,10 +2632,10 @@ class CommandDrawBar : public SBarInfoCommand
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
type = AMMO; type = AMMO;
data.inventoryItem = PClass::FindActor(sc.String); data.inventoryItem = PClass::FindActor(sc.String);
if(data.inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo if(data.inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo
{ {
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
data.inventoryItem = RUNTIME_CLASS(AAmmo); data.inventoryItem = PClass::FindActor(NAME_Ammo);
} }
if(parenthesized) sc.MustGetToken(')'); if(parenthesized) sc.MustGetToken(')');
@ -2825,8 +2827,10 @@ class CommandDrawBar : public SBarInfoCommand
break; break;
case POWERUPTIME: case POWERUPTIME:
{ {
// [value, max] = statusBar.CPlayer.mo.GetEffectTicsForItem(inventoryItem);
// value++; max++;
static VMFunction *func = nullptr; static VMFunction *func = nullptr;
if (func == nullptr) func = static_cast<PFunction*>(RUNTIME_CLASS(APlayerPawn)->Symbols.FindSymbol("GetEffectTicsForItem", false))->Variants[0].Implementation; if (func == nullptr) func = PClass::FindFunction(NAME_PlayerPawn, "GetEffectTicsForItem");
VMValue params[] = { statusBar->CPlayer->mo, data.inventoryItem }; VMValue params[] = { statusBar->CPlayer->mo, data.inventoryItem };
VMReturn ret[2]; VMReturn ret[2];
int ival; int ival;
@ -2840,16 +2844,17 @@ class CommandDrawBar : public SBarInfoCommand
case SAVEPERCENT: case SAVEPERCENT:
{ {
double add = 0; double add = 0;
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>(); auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor);
if (harmor != NULL) if (harmor != NULL)
{ {
add = harmor->Slots[0] + harmor->Slots[1] + double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]; add = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
} }
//Hexen counts basic armor also so we should too. //Hexen counts basic armor also so we should too.
if(statusBar->armor != NULL) if(statusBar->armor != NULL)
{ {
add += statusBar->armor->SavePercent * 100; add += statusBar->armor->FloatVar(NAME_SavePercent) * 100;
} }
value = int(add); value = int(add);
max = 100; max = 100;
@ -3143,12 +3148,12 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl
for(AInventory *inv = statusBar->CPlayer->mo->Inventory;inv != NULL;inv=inv->Inventory) for(AInventory *inv = statusBar->CPlayer->mo->Inventory;inv != NULL;inv=inv->Inventory)
{ {
if(inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder))) auto hc = PClass::FindActor("WeaponHolder");
if(inv->IsKindOf(hc))
{ {
AWeaponHolder *hold = static_cast<AWeaponHolder*>(inv); if(inv->PointerVar<PClass>("PieceWeapon") == weapon)
if(hold->PieceWeapon == weapon)
{ {
SetTruth(0 != (hold->PieceMask & (1 << (piece-1))), block, statusBar); SetTruth(0 != (inv->IntVar("PieceMask") & (1 << (piece-1))), block, statusBar);
return; return;
} }
} }
@ -3312,10 +3317,10 @@ class CommandWeaponAmmo : public SBarInfoNegatableFlowControl
for(int i = 0;i < 2;i++) for(int i = 0;i < 2;i++)
{ {
ammo[i] = PClass::FindClass(sc.String); ammo[i] = PClass::FindClass(sc.String);
if(ammo[i] == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo[i])) //must be a kind of ammo if(ammo[i] == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(ammo[i])) //must be a kind of ammo
{ {
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
ammo[i] = RUNTIME_CLASS(AAmmo); ammo[i] = PClass::FindActor(NAME_Ammo);
} }
if(sc.CheckToken(TK_OrOr)) if(sc.CheckToken(TK_OrOr))
@ -3689,3 +3694,5 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
sc.MustGetToken('}'); sc.MustGetToken('}');
return NULL; return NULL;
} }

View file

@ -43,8 +43,6 @@
#include "c_cvars.h" #include "c_cvars.h"
#include "w_wad.h" #include "w_wad.h"
#include "a_keys.h" #include "a_keys.h"
#include "a_armor.h"
#include "a_ammo.h"
#include "sbar.h" #include "sbar.h"
#include "sc_man.h" #include "sc_man.h"
#include "templates.h" #include "templates.h"
@ -298,7 +296,7 @@ static void DrawHealth(player_t *CPlayer, int x, int y)
const bool haveBerserk = hud_berserk_health const bool haveBerserk = hud_berserk_health
&& nullptr != berserkpic && nullptr != berserkpic
&& nullptr != CPlayer->mo->FindInventory(PClass::FindActor(NAME_PowerStrength)); && nullptr != CPlayer->mo->FindInventory(NAME_PowerStrength);
DrawImageToBox(haveBerserk ? berserkpic : healthpic, x, y, 31, 17); DrawImageToBox(haveBerserk ? berserkpic : healthpic, x, y, 31, 17);
DrawHudNumber(HudFont, fontcolor, health, x + 33, y + 17); DrawHudNumber(HudFont, fontcolor, health, x + 33, y + 17);
@ -311,14 +309,15 @@ static void DrawHealth(player_t *CPlayer, int x, int y)
// //
//=========================================================================== //===========================================================================
static void DrawArmor(ABasicArmor * barmor, AHexenArmor * harmor, int x, int y) static void DrawArmor(AInventory * barmor, AInventory * harmor, int x, int y)
{ {
int ap = 0; int ap = 0;
int bestslot = 4; int bestslot = 4;
if (harmor) if (harmor)
{ {
auto ac = (harmor->Slots[0] + harmor->Slots[1] + harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]); double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
auto ac = (Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4]);
ap += int(ac); ap += int(ac);
if (ac) if (ac)
@ -327,7 +326,7 @@ static void DrawArmor(ABasicArmor * barmor, AHexenArmor * harmor, int x, int y)
bestslot = 0; bestslot = 0;
for (int i = 1; i < 4; ++i) for (int i = 1; i < 4; ++i)
{ {
if (harmor->Slots[i] > harmor->Slots[bestslot]) if (Slots[i] > Slots[bestslot])
{ {
bestslot = i; bestslot = i;
} }
@ -386,9 +385,9 @@ static TArray<PClassActor *> KeyTypes, UnassignedKeyTypes;
static int ktcmp(const void * a, const void * b) static int ktcmp(const void * a, const void * b)
{ {
AKey *key1 = (AKey*)GetDefaultByType ( *(PClassActor **)a ); auto key1 = GetDefaultByType ( *(PClassActor **)a );
AKey *key2 = (AKey*)GetDefaultByType ( *(PClassActor **)b ); auto key2 = GetDefaultByType ( *(PClassActor **)b );
return key1->KeyNumber - key2->KeyNumber; return key1->special1 - key2->special1;
} }
static void SetKeyTypes() static void SetKeyTypes()
@ -396,13 +395,14 @@ static void SetKeyTypes()
for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++) for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++)
{ {
PClass *ti = PClassActor::AllActorClasses[i]; PClass *ti = PClassActor::AllActorClasses[i];
auto kt = PClass::FindActor(NAME_Key);
if (ti->IsDescendantOf(RUNTIME_CLASS(AKey))) if (ti->IsDescendantOf(kt))
{ {
PClassActor *tia = static_cast<PClassActor *>(ti); PClassActor *tia = static_cast<PClassActor *>(ti);
AKey *key = (AKey*)GetDefaultByType(tia); AInventory *key = (AInventory*)(GetDefaultByType(tia));
if (key->Icon.isValid() && key->KeyNumber>0) if (key->Icon.isValid() && key->special1 > 0)
{ {
KeyTypes.Push(tia); KeyTypes.Push(tia);
} }
@ -419,8 +419,7 @@ static void SetKeyTypes()
else else
{ {
// Don't leave the list empty // Don't leave the list empty
PClassActor *ti = RUNTIME_CLASS(AKey); KeyTypes.Push(PClass::FindActor(NAME_Key));
KeyTypes.Push(ti);
} }
} }
@ -527,7 +526,7 @@ static void AddAmmoToList(AWeapon * weapdef)
PClassInventory * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; PClassInventory * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2;
if (ti) if (ti)
{ {
AAmmo * ammodef=(AAmmo*)GetDefaultByType(ti); auto ammodef=(AInventory*)GetDefaultByType(ti);
if (ammodef && !(ammodef->ItemFlags&IF_INVBAR)) if (ammodef && !(ammodef->ItemFlags&IF_INVBAR))
{ {
@ -561,9 +560,9 @@ static void GetAmmoTextLengths(player_t *CPlayer, int& ammocur, int& ammomax)
{ {
for (auto type : orderedammos) for (auto type : orderedammos)
{ {
AAmmo * ammoitem = static_cast<AAmmo*>(CPlayer->mo->FindInventory(type)); auto ammoitem = CPlayer->mo->FindInventory(type);
AAmmo * inv = nullptr == ammoitem auto inv = nullptr == ammoitem
? static_cast<AAmmo*>(GetDefaultByType(type)) ? static_cast<AInventory*>(GetDefaultByType(type))
: ammoitem; : ammoitem;
assert(nullptr != inv); assert(nullptr != inv);
@ -648,9 +647,9 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
{ {
PClassInventory * type = orderedammos[i]; PClassInventory * type = orderedammos[i];
AAmmo * ammoitem = (AAmmo*)CPlayer->mo->FindInventory(type); auto ammoitem = CPlayer->mo->FindInventory(type);
AAmmo * inv = ammoitem? ammoitem : (AAmmo*)GetDefaultByType(orderedammos[i]); auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]);
FTextureID AltIcon = GetHUDIcon(type); FTextureID AltIcon = GetHUDIcon(type);
FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon; FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon;
if (!icon.isValid()) continue; if (!icon.isValid()) continue;
@ -1142,8 +1141,7 @@ void DrawHUD()
DrawFrags(CPlayer, 5, hudheight-70); DrawFrags(CPlayer, 5, hudheight-70);
} }
DrawHealth(CPlayer, 5, hudheight-45); DrawHealth(CPlayer, 5, hudheight-45);
DrawArmor(CPlayer->mo->FindInventory<ABasicArmor>(), DrawArmor(CPlayer->mo->FindInventory(NAME_BasicArmor), CPlayer->mo->FindInventory(NAME_HexenArmor), 5, hudheight-20);
CPlayer->mo->FindInventory<AHexenArmor>(), 5, hudheight-20);
i=DrawKeys(CPlayer, hudwidth-4, hudheight-10); i=DrawKeys(CPlayer, hudwidth-4, hudheight-10);
i=DrawAmmo(CPlayer, hudwidth-5, i); i=DrawAmmo(CPlayer, hudwidth-5, i);
if (hud_showweapons) DrawWeapons(CPlayer, hudwidth - 5, i); if (hud_showweapons) DrawWeapons(CPlayer, hudwidth - 5, i);

View file

@ -1794,7 +1794,7 @@ AInventory *DBaseStatusBar::ValidateInvFirst (int numVisible) const
// //
//============================================================================ //============================================================================
void DBaseStatusBar::GetCurrentAmmo (AAmmo *&ammo1, AAmmo *&ammo2, int &ammocount1, int &ammocount2) const void DBaseStatusBar::GetCurrentAmmo (AInventory *&ammo1, AInventory *&ammo2, int &ammocount1, int &ammocount2) const
{ {
if (CPlayer->ReadyWeapon != NULL) if (CPlayer->ReadyWeapon != NULL)
{ {

View file

@ -12,8 +12,6 @@
#include "m_swap.h" #include "m_swap.h"
#include "templates.h" #include "templates.h"
#include "a_keys.h" #include "a_keys.h"
#include "a_armor.h"
#include "a_ammo.h"
#include "gi.h" #include "gi.h"
#include "g_level.h" #include "g_level.h"
#include "colormatcher.h" #include "colormatcher.h"
@ -257,7 +255,7 @@ public:
item != NULL; item != NULL;
item = item->Inventory) item = item->Inventory)
{ {
if (item->IsKindOf (RUNTIME_CLASS(AKey))) if (item->IsKindOf (PClass::FindActor(NAME_Key)))
{ {
if (i == KeyPopPos) if (i == KeyPopPos)
{ {
@ -404,7 +402,7 @@ private:
DrawImage (&HealthBar, 49, 7); DrawImage (&HealthBar, 49, 7);
// Armor // Armor
item = CPlayer->mo->FindInventory<ABasicArmor>(); item = CPlayer->mo->FindInventory(NAME_BasicArmor);
if (item != NULL && item->Amount > 0) if (item != NULL && item->Amount > 0)
{ {
DrawImage (TexMan(item->Icon), 2, 9); DrawImage (TexMan(item->Icon), 2, 9);
@ -412,7 +410,7 @@ private:
} }
// Ammo // Ammo
AAmmo *ammo1, *ammo2; AInventory *ammo1, *ammo2;
int ammocount1, ammocount2; int ammocount1, ammocount2;
GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2); GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2);
@ -432,7 +430,7 @@ private:
} }
// Sigil // Sigil
item = CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil)); item = CPlayer->mo->FindInventory(NAME_Sigil);
if (item != NULL) if (item != NULL)
{ {
DrawImage (TexMan(item->Icon), 253, 7); DrawImage (TexMan(item->Icon), 253, 7);
@ -469,7 +467,7 @@ private:
TAG_DONE); TAG_DONE);
// Draw armor // Draw armor
ABasicArmor *armor = CPlayer->mo->FindInventory<ABasicArmor>(); auto armor = CPlayer->mo->FindInventory(NAME_BasicArmor);
if (armor != NULL && armor->Amount != 0) if (armor != NULL && armor->Amount != 0)
{ {
DrINumberOuter (armor->Amount, 35, -10, false, 7); DrINumberOuter (armor->Amount, 35, -10, false, 7);
@ -480,7 +478,7 @@ private:
} }
// Draw ammo // Draw ammo
AAmmo *ammo1, *ammo2; AInventory *ammo1, *ammo2;
int ammocount1, ammocount2; int ammocount1, ammocount2;
GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2); GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2);
@ -629,7 +627,7 @@ private:
i < endpos && item != NULL; i < endpos && item != NULL;
item = item->Inventory) item = item->Inventory)
{ {
if (!item->IsKindOf (RUNTIME_CLASS(AKey))) if (!item->IsKindOf (PClass::FindActor(NAME_Key)))
continue; continue;
if (i < pos) if (i < pos)
@ -674,7 +672,7 @@ private:
item != NULL; item != NULL;
item = item->Inventory) item = item->Inventory)
{ {
if (item->IsKindOf (RUNTIME_CLASS(AKey))) if (item->IsKindOf (PClass::FindActor(NAME_Key)))
{ {
i++; i++;
} }

View file

@ -47,6 +47,8 @@ gameinfo_t gameinfo;
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon1)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2)
const char *GameNames[17] = const char *GameNames[17] =

View file

@ -109,49 +109,6 @@ DEFINE_CLASS_PROPERTY(type, S, DynamicLight)
// //
//========================================================================== //==========================================================================
IMPLEMENT_CLASS(ADynamicLight, false, false) IMPLEMENT_CLASS(ADynamicLight, false, false)
IMPLEMENT_CLASS(AVavoomLight, false, false)
IMPLEMENT_CLASS(AVavoomLightWhite, false, false)
IMPLEMENT_CLASS(AVavoomLightColor, false, false)
void AVavoomLight::BeginPlay ()
{
// This must not call Super::BeginPlay!
ChangeStatNum(STAT_DLIGHT);
if (Sector) AddZ(-Sector->floorplane.ZatPoint(this), false);
lighttype = PointLight;
}
void AVavoomLightWhite::BeginPlay ()
{
m_Radius[0] = args[0] * 4;
args[LIGHT_RED] = 128;
args[LIGHT_GREEN] = 128;
args[LIGHT_BLUE] = 128;
if (gl.legacyMode && (flags4 & MF4_ATTENUATE))
{
m_Radius[0] = m_Radius[0] * 2 / 3;
}
Super::BeginPlay();
}
void AVavoomLightColor::BeginPlay ()
{
int l_args[5];
memcpy(l_args, args, sizeof(l_args));
memset(args, 0, sizeof(args));
m_Radius[0] = l_args[0] * 4;
args[LIGHT_RED] = l_args[1] >> 1;
args[LIGHT_GREEN] = l_args[2] >> 1;
args[LIGHT_BLUE] = l_args[3] >> 1;
if (gl.legacyMode && (flags4 & MF4_ATTENUATE))
{
m_Radius[0] = m_Radius[0] * 2 / 3;
}
Super::BeginPlay();
}
static FRandom randLight; static FRandom randLight;
@ -173,8 +130,7 @@ void ADynamicLight::Serialize(FSerializer &arc)
arc("lightflags", lightflags, def->lightflags) arc("lightflags", lightflags, def->lightflags)
("lighttype", lighttype, def->lighttype) ("lighttype", lighttype, def->lighttype)
("tickcount", m_tickCount, def->m_tickCount) ("tickcount", m_tickCount, def->m_tickCount)
("currentradius", m_currentRadius, def->m_currentRadius) ("currentradius", m_currentRadius, def->m_currentRadius);
.Array("lightradius", m_Radius, def->m_Radius, 2);
if (lighttype == PulseLight) if (lighttype == PulseLight)
arc("lastupdate", m_lastUpdate, def->m_lastUpdate) arc("lastupdate", m_lastUpdate, def->m_lastUpdate)
@ -201,15 +157,13 @@ void ADynamicLight::BeginPlay()
//Super::BeginPlay(); //Super::BeginPlay();
ChangeStatNum(STAT_DLIGHT); ChangeStatNum(STAT_DLIGHT);
m_Radius[0] = args[LIGHT_INTENSITY];
m_Radius[1] = args[LIGHT_SECONDARY_INTENSITY];
specialf1 = DAngle(double(SpawnAngle)).Normalized360().Degrees; specialf1 = DAngle(double(SpawnAngle)).Normalized360().Degrees;
visibletoplayer = true; visibletoplayer = true;
if (gl.legacyMode && (flags4 & MF4_ATTENUATE)) if (gl.legacyMode && (flags4 & MF4_ATTENUATE))
{ {
m_Radius[0] = m_Radius[0] * 2 / 3; args[LIGHT_INTENSITY] = args[LIGHT_INTENSITY] * 2 / 3;
m_Radius[1] = m_Radius[1] * 2 / 3; args[LIGHT_SECONDARY_INTENSITY] = args[LIGHT_SECONDARY_INTENSITY] * 2 / 3;
} }
} }
@ -241,7 +195,7 @@ void ADynamicLight::Activate(AActor *activator)
//Super::Activate(activator); //Super::Activate(activator);
flags2&=~MF2_DORMANT; flags2&=~MF2_DORMANT;
m_currentRadius = float(m_Radius[0]); m_currentRadius = float(args[LIGHT_INTENSITY]);
m_tickCount = 0; m_tickCount = 0;
if (lighttype == PulseLight) if (lighttype == PulseLight)
@ -249,7 +203,7 @@ void ADynamicLight::Activate(AActor *activator)
float pulseTime = specialf1 / TICRATE; float pulseTime = specialf1 / TICRATE;
m_lastUpdate = level.maptime; m_lastUpdate = level.maptime;
m_cycler.SetParams(float(m_Radius[1]), float(m_Radius[0]), pulseTime); m_cycler.SetParams(float(args[LIGHT_SECONDARY_INTENSITY]), float(args[LIGHT_INTENSITY]), pulseTime);
m_cycler.ShouldCycle(true); m_cycler.ShouldCycle(true);
m_cycler.SetCycleType(CYCLE_Sin); m_cycler.SetCycleType(CYCLE_Sin);
m_currentRadius = m_cycler.GetVal(); m_currentRadius = m_cycler.GetVal();
@ -309,22 +263,22 @@ void ADynamicLight::Tick()
BYTE rnd = randLight(); BYTE rnd = randLight();
float pct = specialf1 / 360.f; float pct = specialf1 / 360.f;
m_currentRadius = float(m_Radius[rnd >= pct * 255]); m_currentRadius = float(args[LIGHT_INTENSITY + (rnd >= pct * 255)]);
break; break;
} }
case RandomFlickerLight: case RandomFlickerLight:
{ {
int flickerRange = m_Radius[1] - m_Radius[0]; int flickerRange = args[LIGHT_SECONDARY_INTENSITY] - args[LIGHT_INTENSITY];
float amt = randLight() / 255.f; float amt = randLight() / 255.f;
if (m_tickCount > specialf1) if (m_tickCount > specialf1)
{ {
m_tickCount = 0; m_tickCount = 0;
} }
if (m_tickCount++ == 0 || m_currentRadius > m_Radius[1]) if (m_tickCount++ == 0 || m_currentRadius > args[LIGHT_SECONDARY_INTENSITY])
{ {
m_currentRadius = float(m_Radius[0] + (amt * flickerRange)); m_currentRadius = float(args[LIGHT_INTENSITY] + (amt * flickerRange));
} }
break; break;
} }
@ -342,14 +296,14 @@ void ADynamicLight::Tick()
case RandomColorFlickerLight: case RandomColorFlickerLight:
{ {
int flickerRange = m_Radius[1] - m_Radius[0]; int flickerRange = args[LIGHT_SECONDARY_INTENSITY] - args[LIGHT_INTENSITY];
float amt = randLight() / 255.f; float amt = randLight() / 255.f;
m_tickCount++; m_tickCount++;
if (m_tickCount > specialf1) if (m_tickCount > specialf1)
{ {
m_currentRadius = m_Radius[0] + (amt * flickerRange); m_currentRadius = args[LIGHT_INTENSITY] + (amt * flickerRange);
m_tickCount = 0; m_tickCount = 0;
} }
break; break;
@ -371,7 +325,7 @@ void ADynamicLight::Tick()
} }
case PointLight: case PointLight:
m_currentRadius = float(m_Radius[0]); m_currentRadius = float(args[LIGHT_INTENSITY]);
break; break;
} }
UpdateLocation(); UpdateLocation();
@ -423,7 +377,7 @@ void ADynamicLight::UpdateLocation()
if (lighttype == FlickerLight || lighttype == RandomFlickerLight || lighttype == PulseLight) if (lighttype == FlickerLight || lighttype == RandomFlickerLight || lighttype == PulseLight)
{ {
intensity = float(MAX(m_Radius[0], m_Radius[1])); intensity = float(MAX(args[LIGHT_INTENSITY], args[LIGHT_SECONDARY_INTENSITY]));
} }
else else
{ {

View file

@ -178,8 +178,8 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const
light->SetOffset(m_Pos); light->SetOffset(m_Pos);
light->halo = m_halo; light->halo = m_halo;
for (int a = 0; a < 3; a++) light->args[a] = clamp<int>((int)(m_Args[a]), 0, 255); for (int a = 0; a < 3; a++) light->args[a] = clamp<int>((int)(m_Args[a]), 0, 255);
light->m_Radius[0] = int(m_Args[LIGHT_INTENSITY]); light->args[LIGHT_INTENSITY] = int(m_Args[LIGHT_INTENSITY]);
light->m_Radius[1] = int(m_Args[LIGHT_SECONDARY_INTENSITY]); light->args[LIGHT_SECONDARY_INTENSITY] = int(m_Args[LIGHT_SECONDARY_INTENSITY]);
light->flags4 &= ~(MF4_ADDITIVE | MF4_SUBTRACTIVE | MF4_DONTLIGHTSELF); light->flags4 &= ~(MF4_ADDITIVE | MF4_SUBTRACTIVE | MF4_DONTLIGHTSELF);
if (m_subtractive) light->flags4 |= MF4_SUBTRACTIVE; if (m_subtractive) light->flags4 |= MF4_SUBTRACTIVE;
if (m_additive) light->flags4 |= MF4_ADDITIVE; if (m_additive) light->flags4 |= MF4_ADDITIVE;
@ -190,7 +190,7 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const
float pulseTime = float(m_Param / TICRATE); float pulseTime = float(m_Param / TICRATE);
light->m_lastUpdate = level.maptime; light->m_lastUpdate = level.maptime;
light->m_cycler.SetParams(float(light->m_Radius[1]), float(light->m_Radius[0]), pulseTime, oldtype == PulseLight); light->m_cycler.SetParams(float(light->args[LIGHT_SECONDARY_INTENSITY]), float(light->args[LIGHT_INTENSITY]), pulseTime, oldtype == PulseLight);
light->m_cycler.ShouldCycle(true); light->m_cycler.ShouldCycle(true);
light->m_cycler.SetCycleType(CYCLE_Sin); light->m_cycler.SetCycleType(CYCLE_Sin);
light->m_currentRadius = light->m_cycler.GetVal(); light->m_currentRadius = light->m_cycler.GetVal();

View file

@ -135,7 +135,6 @@ protected:
public: public:
int m_tickCount; int m_tickCount;
int m_Radius[2];
BYTE lightflags; BYTE lightflags;
BYTE lighttype; BYTE lighttype;
bool owned; bool owned;
@ -147,28 +146,6 @@ public:
}; };
class AVavoomLight : public ADynamicLight
{
DECLARE_CLASS (AVavoomLight, ADynamicLight)
public:
virtual void BeginPlay();
};
class AVavoomLightWhite : public AVavoomLight
{
DECLARE_CLASS (AVavoomLightWhite, AVavoomLight)
public:
virtual void BeginPlay();
};
class AVavoomLightColor : public AVavoomLight
{
DECLARE_CLASS (AVavoomLightColor, AVavoomLight)
public:
void BeginPlay();
};
enum enum
{ {
STAT_DLIGHT=64 STAT_DLIGHT=64

View file

@ -758,6 +758,14 @@ bool DamageTypeDefinition::IgnoreArmor(FName type)
return false; return false;
} }
DEFINE_ACTION_FUNCTION(_DamageTypeDefinition, IgnoreArmor)
{
PARAM_PROLOGUE;
PARAM_NAME(type);
ACTION_RETURN_BOOL(DamageTypeDefinition::IgnoreArmor(type));
}
//========================================================================== //==========================================================================
// //
// DamageTypeDefinition :: ApplyMobjDamageFactor // DamageTypeDefinition :: ApplyMobjDamageFactor

View file

@ -226,10 +226,12 @@ public:
NoArmor = false; NoArmor = false;
} }
static DamageTypeDefinition *Get(FName type);
static bool IgnoreArmor(FName type); static bool IgnoreArmor(FName type);
static double GetMobjDamageFactor(FName type, DmgFactors const * const factors);
static int ApplyMobjDamageFactor(int damage, FName type, DmgFactors const * const factors); static int ApplyMobjDamageFactor(int damage, FName type, DmgFactors const * const factors);
private:
static double GetMobjDamageFactor(FName type, DmgFactors const * const factors);
static DamageTypeDefinition *Get(FName type);
}; };
class DDropItem; class DDropItem;

View file

@ -47,8 +47,6 @@
#include "serializer.h" #include "serializer.h"
#include "r_utility.h" #include "r_utility.h"
#include "a_morph.h" #include "a_morph.h"
#include "a_armor.h"
#include "a_ammo.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "virtual.h" #include "virtual.h"
@ -267,7 +265,7 @@ void cht_DoCheat (player_t *player, int cheat)
} }
else if (player->mo != NULL && player->health >= 0) else if (player->mo != NULL && player->health >= 0)
{ {
item = player->mo->FindInventory(PClass::FindActor(BeholdPowers[i])); item = player->mo->FindInventory(BeholdPowers[i]);
if (item == NULL) if (item == NULL)
{ {
if (i != 0) if (i != 0)
@ -319,7 +317,7 @@ void cht_DoCheat (player_t *player, int cheat)
case CHT_RESSURECT: case CHT_RESSURECT:
if (player->playerstate != PST_LIVE && player->mo != nullptr) if (player->playerstate != PST_LIVE && player->mo != nullptr)
{ {
if (player->mo->IsKindOf(RUNTIME_CLASS(APlayerChunk))) if (player->mo->IsKindOf(PClass::FindActor("PlayerChunk")))
{ {
Printf("Unable to resurrect. Player is no longer connected to its body.\n"); Printf("Unable to resurrect. Player is no longer connected to its body.\n");
} }
@ -488,7 +486,7 @@ void cht_DoCheat (player_t *player, int cheat)
int oldpieces = 1; int oldpieces = 1;
ret.IntAt(&oldpieces); ret.IntAt(&oldpieces);
GlobalVMStack.Call(gsp, params, 1, &ret, 1, nullptr); GlobalVMStack.Call(gsp, params, 1, &ret, 1, nullptr);
item = player->mo->FindInventory(PClass::FindActor(NAME_Sigil)); item = player->mo->FindInventory(NAME_Sigil);
if (item != NULL) if (item != NULL)
{ {

View file

@ -83,6 +83,20 @@ xx(PointPuller)
xx(UpperStackLookOnly) xx(UpperStackLookOnly)
xx(LowerStackLookOnly) xx(LowerStackLookOnly)
xx(BasicArmorBonus)
xx(BasicArmorPickup)
xx(SaveAmount)
xx(SavePercent)
xx(MaxAbsorb)
xx(MaxFullAbsorb)
xx(MaxAmount)
xx(ActualSaveAmount)
xx(ArmorType)
xx(HexenArmor)
xx(Slots)
xx(SlotsIncrement)
xx(BulletPuff) xx(BulletPuff)
xx(StrifePuff) xx(StrifePuff)
xx(MaulerPuff) xx(MaulerPuff)
@ -716,6 +730,8 @@ xx(BlendColor)
xx(Strength) xx(Strength)
xx(Mode) xx(Mode)
xx(PowerupType) xx(PowerupType)
xx(PlayerPawn)
xx(Key)
// Decorate compatibility functions // Decorate compatibility functions
xx(BuiltinTypeCheck) xx(BuiltinTypeCheck)

View file

@ -83,8 +83,6 @@
#include "serializer.h" #include "serializer.h"
#include "thingdef.h" #include "thingdef.h"
#include "a_pickups.h" #include "a_pickups.h"
#include "a_armor.h"
#include "a_ammo.h"
#include "r_data/colormaps.h" #include "r_data/colormaps.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "stats.h" #include "stats.h"
@ -4956,8 +4954,8 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
else else
{ {
FName p(FBehavior::StaticLookupString(args[0])); FName p(FBehavior::StaticLookupString(args[0]));
ABasicArmor * armor = (ABasicArmor *) players[args[1]].mo->FindInventory(NAME_BasicArmor); auto armor = players[args[1]].mo->FindInventory(NAME_BasicArmor);
if (armor && armor->ArmorType == p) return armor->Amount; if (armor && armor->NameVar(NAME_ArmorType) == p) return armor->Amount;
} }
return 0; return 0;
} }
@ -4966,29 +4964,29 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
{ {
if (activator == NULL || activator->player == NULL) return 0; if (activator == NULL || activator->player == NULL) return 0;
ABasicArmor * equippedarmor = (ABasicArmor *) activator->FindInventory(NAME_BasicArmor); auto equippedarmor = activator->FindInventory(NAME_BasicArmor);
if (equippedarmor && equippedarmor->Amount != 0) if (equippedarmor && equippedarmor->Amount != 0)
{ {
switch(args[0]) switch(args[0])
{ {
case ARMORINFO_CLASSNAME: case ARMORINFO_CLASSNAME:
return GlobalACSStrings.AddString(equippedarmor->ArmorType.GetChars()); return GlobalACSStrings.AddString(equippedarmor->NameVar(NAME_ArmorType).GetChars());
case ARMORINFO_SAVEAMOUNT: case ARMORINFO_SAVEAMOUNT:
return equippedarmor->MaxAmount; return equippedarmor->IntVar(NAME_MaxAmount);
case ARMORINFO_SAVEPERCENT: case ARMORINFO_SAVEPERCENT:
return DoubleToACS(equippedarmor->SavePercent); return DoubleToACS(equippedarmor->FloatVar(NAME_SavePercent));
case ARMORINFO_MAXABSORB: case ARMORINFO_MAXABSORB:
return equippedarmor->MaxAbsorb; return equippedarmor->IntVar(NAME_MaxAbsorb);
case ARMORINFO_MAXFULLABSORB: case ARMORINFO_MAXFULLABSORB:
return equippedarmor->MaxFullAbsorb; return equippedarmor->IntVar(NAME_MaxFullAbsorb);
case ARMORINFO_ACTUALSAVEAMOUNT: case ARMORINFO_ACTUALSAVEAMOUNT:
return equippedarmor->ActualSaveAmount; return equippedarmor->IntVar(NAME_ActualSaveAmount);
default: default:
return 0; return 0;
@ -8236,7 +8234,7 @@ scriptwait:
case PCD_PLAYERARMORPOINTS: case PCD_PLAYERARMORPOINTS:
if (activator) if (activator)
{ {
ABasicArmor *armor = activator->FindInventory<ABasicArmor>(); auto armor = activator->FindInventory(NAME_BasicArmor);
PushToStack (armor ? armor->Amount : 0); PushToStack (armor ? armor->Amount : 0);
} }
else else
@ -8683,7 +8681,7 @@ scriptwait:
{ {
AInventory *sigil; AInventory *sigil;
if (activator == NULL || (sigil = activator->FindInventory(PClass::FindActor(NAME_Sigil))) == NULL) if (activator == NULL || (sigil = activator->FindInventory(NAME_Sigil)) == NULL)
{ {
PushToStack (0); PushToStack (0);
} }
@ -8700,7 +8698,7 @@ scriptwait:
PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(1))); PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(1)));
AInventory *item; AInventory *item;
if (type != NULL && type->ParentClass == RUNTIME_CLASS(AAmmo)) if (type != NULL && type->ParentClass == PClass::FindActor(NAME_Ammo))
{ {
item = activator->FindInventory (static_cast<PClassActor *>(type)); item = activator->FindInventory (static_cast<PClassActor *>(type));
if (item != NULL) if (item != NULL)
@ -8729,7 +8727,7 @@ scriptwait:
PClassActor *type = PClass::FindActor (FBehavior::StaticLookupString (STACK(2))); PClassActor *type = PClass::FindActor (FBehavior::StaticLookupString (STACK(2)));
AInventory *item; AInventory *item;
if (type != NULL && type->ParentClass == RUNTIME_CLASS(AAmmo)) if (type != NULL && type->ParentClass == PClass::FindActor(NAME_Ammo))
{ {
item = activator->FindInventory (type); item = activator->FindInventory (type);
if (item != NULL) if (item != NULL)

View file

@ -78,7 +78,6 @@
#include "v_text.h" #include "v_text.h"
#include "thingdef.h" #include "thingdef.h"
#include "math/cmath.h" #include "math/cmath.h"
#include "a_armor.h"
#include "g_levellocals.h" #include "g_levellocals.h"
AActor *SingleActorFromTID(int tid, AActor *defactor); AActor *SingleActorFromTID(int tid, AActor *defactor);
@ -2059,7 +2058,7 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_CustomPunch)
PARAM_FLOAT_DEF (range); PARAM_FLOAT_DEF (range);
PARAM_FLOAT_DEF (lifesteal); PARAM_FLOAT_DEF (lifesteal);
PARAM_INT_DEF (lifestealmax); PARAM_INT_DEF (lifestealmax);
PARAM_CLASS_DEF (armorbonustype, ABasicArmorBonus); PARAM_CLASS_DEF (armorbonustype, AActor);
PARAM_SOUND_DEF (MeleeSound); PARAM_SOUND_DEF (MeleeSound);
PARAM_SOUND_DEF (MissSound); PARAM_SOUND_DEF (MissSound);
@ -2107,18 +2106,17 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_CustomPunch)
{ {
if (armorbonustype == NULL) if (armorbonustype == NULL)
{ {
armorbonustype = dyn_cast<ABasicArmorBonus::MetaClass>(PClass::FindClass("ArmorBonus")); armorbonustype = PClass::FindActor("ArmorBonus");
} }
if (armorbonustype != NULL) if (armorbonustype != NULL)
{ {
assert(armorbonustype->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))); auto armorbonus = Spawn(armorbonustype);
ABasicArmorBonus *armorbonus = static_cast<ABasicArmorBonus *>(Spawn(armorbonustype)); armorbonus->IntVar(NAME_SaveAmount) *= int(actualdamage * lifesteal);
armorbonus->SaveAmount *= int(actualdamage * lifesteal); if (lifestealmax > 0) armorbonus->IntVar("MaxSaveAmount") = lifestealmax;
armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax;
armorbonus->flags |= MF_DROPPED; armorbonus->flags |= MF_DROPPED;
armorbonus->ClearCounters(); armorbonus->ClearCounters();
if (!armorbonus->CallTryPickup(self)) if (!static_cast<AInventory*>(armorbonus)->CallTryPickup(self))
{ {
armorbonus->Destroy (); armorbonus->Destroy ();
} }

View file

@ -642,7 +642,7 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount)
return; return;
// Don't take keys. // Don't take keys.
if (itemtype->IsDescendantOf (RUNTIME_CLASS(AKey))) if (itemtype->IsDescendantOf (PClass::FindActor(NAME_Key)))
return; return;
// Don't take the sigil. // Don't take the sigil.

View file

@ -51,7 +51,6 @@
#include "p_spec.h" #include "p_spec.h"
#include "p_checkposition.h" #include "p_checkposition.h"
#include "math/cmath.h" #include "math/cmath.h"
#include "a_ammo.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "gi.h" #include "gi.h"
@ -3228,7 +3227,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount)
if (dropamount > 0) if (dropamount > 0)
{ {
if (flagmask != 0 && inv->IsKindOf(RUNTIME_CLASS(AAmmo))) if (flagmask != 0 && inv->IsKindOf(PClass::FindActor(NAME_Ammo)))
{ {
inv->Amount = int(dropamount * dropammofactor); inv->Amount = int(dropamount * dropammofactor);
inv->ItemFlags |= IF_IGNORESKILL; inv->ItemFlags |= IF_IGNORESKILL;
@ -3238,10 +3237,10 @@ void ModifyDropAmount(AInventory *inv, int dropamount)
inv->Amount = dropamount; inv->Amount = dropamount;
} }
} }
else if (inv->IsKindOf (RUNTIME_CLASS(AAmmo))) else if (inv->IsKindOf (PClass::FindActor(NAME_Ammo)))
{ {
// Half ammo when dropped by bad guys. // Half ammo when dropped by bad guys.
int amount = static_cast<AAmmo *>(inv)->DropAmount; int amount = inv->IntVar("DropAmount");
if (amount <= 0) if (amount <= 0)
{ {
amount = MAX(1, int(inv->Amount * dropammofactor)); amount = MAX(1, int(inv->Amount * dropammofactor));

View file

@ -1456,7 +1456,7 @@ void P_SetRenderSector()
segs[i].PartnerSeg = segs[i].PartnerSeg->PartnerSeg = nullptr; segs[i].PartnerSeg = segs[i].PartnerSeg->PartnerSeg = nullptr;
} }
} }
}
for (i = 0; i < numsegs; i++) for (i = 0; i < numsegs; i++)
{ {
if (segs[i].PartnerSeg != nullptr && segs[i].PartnerSeg->PartnerSeg != &segs[i]) if (segs[i].PartnerSeg != nullptr && segs[i].PartnerSeg->PartnerSeg != &segs[i])
@ -1464,7 +1464,6 @@ void P_SetRenderSector()
segs[i].PartnerSeg = nullptr; segs[i].PartnerSeg = nullptr;
} }
} }
}
// look up sector number for each subsector // look up sector number for each subsector
for (i = 0; i < numsubsectors; i++) for (i = 0; i < numsubsectors; i++)

View file

@ -2883,7 +2883,7 @@ FUNC(LS_SetPlayerProperty)
{ // Take power from activator { // Take power from activator
if (power != 4) if (power != 4)
{ {
AInventory *item = it->FindInventory(PClass::FindActor(powers[power]), true); AInventory *item = it->FindInventory(powers[power], true);
if (item != NULL) if (item != NULL)
{ {
item->Destroy (); item->Destroy ();

View file

@ -69,8 +69,6 @@
#include "thingdef.h" #include "thingdef.h"
#include "d_player.h" #include "d_player.h"
#include "virtual.h" #include "virtual.h"
#include "a_armor.h"
#include "a_ammo.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "a_morph.h" #include "a_morph.h"
@ -791,13 +789,9 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat)
item->ClearCounters(); item->ClearCounters();
if (!givecheat || amount > 0) if (!givecheat || amount > 0)
{ {
if (type->IsDescendantOf (RUNTIME_CLASS(ABasicArmorPickup))) if (type->IsDescendantOf (PClass::FindActor(NAME_BasicArmorPickup)) || type->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus)))
{ {
static_cast<ABasicArmorPickup*>(item)->SaveAmount *= amount; item->IntVar(NAME_SaveAmount) *= amount;
}
else if (type->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus)))
{
static_cast<ABasicArmorBonus*>(item)->SaveAmount *= amount;
} }
else else
{ {
@ -899,14 +893,11 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate
result = true; result = true;
} }
if (item->IsKindOf(RUNTIME_CLASS(AHexenArmor)))
return false;
// Do not take ammo if the "no take infinite/take as ammo depletion" flag is set // Do not take ammo if the "no take infinite/take as ammo depletion" flag is set
// and infinite ammo is on // and infinite ammo is on
if (notakeinfinite && if (notakeinfinite &&
((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) && ((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) &&
item->IsKindOf(RUNTIME_CLASS(AAmmo))) item->IsKindOf(PClass::FindActor(NAME_Ammo)))
{ {
// Nothing to do here, except maybe res = false;? Would it make sense? // Nothing to do here, except maybe res = false;? Would it make sense?
result = false; result = false;
@ -1098,9 +1089,9 @@ AInventory *AActor::FindInventory (PClassActor *type, bool subclass)
return item; return item;
} }
AInventory *AActor::FindInventory (FName type) AInventory *AActor::FindInventory (FName type, bool subclass)
{ {
return FindInventory(PClass::FindActor(type)); return FindInventory(PClass::FindActor(type), subclass);
} }
DEFINE_ACTION_FUNCTION(AActor, FindInventory) DEFINE_ACTION_FUNCTION(AActor, FindInventory)
@ -1171,7 +1162,7 @@ bool AActor::GiveAmmo (PClassInventory *type, int amount)
DEFINE_ACTION_FUNCTION(AActor, GiveAmmo) DEFINE_ACTION_FUNCTION(AActor, GiveAmmo)
{ {
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(type, AAmmo); PARAM_CLASS(type, AInventory);
PARAM_INT(amount); PARAM_INT(amount);
ACTION_RETURN_BOOL(self->GiveAmmo(type, amount)); ACTION_RETURN_BOOL(self->GiveAmmo(type, amount));
} }
@ -1212,12 +1203,7 @@ void AActor::ClearInventory()
if (!(inv->ItemFlags & IF_UNDROPPABLE)) if (!(inv->ItemFlags & IF_UNDROPPABLE))
{ {
inv->DepleteOrDestroy(); inv->DepleteOrDestroy();
} if (!(inv->ObjectFlags & OF_EuthanizeMe)) invp = &inv->Inventory; // was only depleted so advance the pointer manually.
else if (inv->GetClass() == RUNTIME_CLASS(AHexenArmor))
{
AHexenArmor *harmor = static_cast<AHexenArmor *> (inv);
harmor->Slots[3] = harmor->Slots[2] = harmor->Slots[1] = harmor->Slots[0] = 0;
invp = &inv->Inventory;
} }
else else
{ {
@ -5711,7 +5697,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
} }
if (dmflags & DF_NO_ARMOR) if (dmflags & DF_NO_ARMOR)
{ {
if (i->IsDescendantOf (RUNTIME_CLASS(AArmor))) if (i->IsDescendantOf (PClass::FindActor(NAME_Armor)))
return NULL; return NULL;
if (i->TypeName == NAME_Megasphere) if (i->TypeName == NAME_Megasphere)
return NULL; return NULL;

View file

@ -237,7 +237,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer)
{ {
if (mo != nullptr) if (mo != nullptr)
{ {
newcaller = mo->FindInventory(PClass::FindActor(NAME_PowerTargeter), true); newcaller = mo->FindInventory(NAME_PowerTargeter, true);
} }
} }
else if (layer == PSP_STRIFEHANDS) else if (layer == PSP_STRIFEHANDS)

View file

@ -59,8 +59,6 @@
#include "a_morph.h" #include "a_morph.h"
#include "p_spec.h" #include "p_spec.h"
#include "virtual.h" #include "virtual.h"
#include "a_armor.h"
#include "a_ammo.h"
#include "g_levellocals.h" #include "g_levellocals.h"
static FRandom pr_skullpop ("SkullPop"); static FRandom pr_skullpop ("SkullPop");
@ -660,8 +658,6 @@ IMPLEMENT_POINTERS_START(APlayerPawn)
IMPLEMENT_POINTER(FlechetteType) IMPLEMENT_POINTER(FlechetteType)
IMPLEMENT_POINTERS_END IMPLEMENT_POINTERS_END
IMPLEMENT_CLASS(APlayerChunk, false, false)
void APlayerPawn::Serialize(FSerializer &arc) void APlayerPawn::Serialize(FSerializer &arc)
{ {
Super::Serialize (arc); Super::Serialize (arc);
@ -1076,12 +1072,12 @@ void APlayerPawn::GiveDeathmatchInventory()
{ {
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
{ {
if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) if (PClassActor::AllActorClasses[i]->IsDescendantOf (PClass::FindActor(NAME_Key)))
{ {
AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]); AInventory *key = (AInventory*)GetDefaultByType (PClassActor::AllActorClasses[i]);
if (key->KeyNumber != 0) if (key->special1 != 0)
{ {
key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClassActor::AllActorClasses[i]))); key = (AInventory*)Spawn(PClassActor::AllActorClasses[i]);
if (!key->CallTryPickup (this)) if (!key->CallTryPickup (this))
{ {
key->Destroy (); key->Destroy ();
@ -1134,7 +1130,7 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
if ((dmflags & DF_COOP_LOSE_KEYS) && if ((dmflags & DF_COOP_LOSE_KEYS) &&
defitem == NULL && defitem == NULL &&
item->IsKindOf(RUNTIME_CLASS(AKey))) item->IsKindOf(PClass::FindActor(NAME_Key)))
{ {
item->Destroy(); item->Destroy();
} }
@ -1145,23 +1141,22 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
item->Destroy(); item->Destroy();
} }
else if ((dmflags & DF_COOP_LOSE_ARMOR) && else if ((dmflags & DF_COOP_LOSE_ARMOR) &&
item->IsKindOf(RUNTIME_CLASS(AArmor))) item->IsKindOf(PClass::FindActor(NAME_Armor)))
{ {
if (defitem == NULL) if (defitem == NULL)
{ {
item->Destroy(); item->Destroy();
} }
else if (item->IsKindOf(RUNTIME_CLASS(ABasicArmor))) else if (item->IsKindOf(PClass::FindActor(NAME_BasicArmor)))
{ {
static_cast<ABasicArmor*>(item)->SavePercent = static_cast<ABasicArmor*>(defitem)->SavePercent; item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent);
item->Amount = defitem->Amount; item->Amount = defitem->Amount;
} }
else if (item->IsKindOf(RUNTIME_CLASS(AHexenArmor))) else if (item->IsKindOf(PClass::FindActor(NAME_HexenArmor)))
{ {
static_cast<AHexenArmor*>(item)->Slots[0] = static_cast<AHexenArmor*>(defitem)->Slots[0]; double *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr);
static_cast<AHexenArmor*>(item)->Slots[1] = static_cast<AHexenArmor*>(defitem)->Slots[1]; double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr);
static_cast<AHexenArmor*>(item)->Slots[2] = static_cast<AHexenArmor*>(defitem)->Slots[2]; memcpy(SlotsTo, SlotsFrom, 4 * sizeof(double));
static_cast<AHexenArmor*>(item)->Slots[3] = static_cast<AHexenArmor*>(defitem)->Slots[3];
} }
} }
else if ((dmflags & DF_COOP_LOSE_POWERUPS) && else if ((dmflags & DF_COOP_LOSE_POWERUPS) &&
@ -1171,7 +1166,7 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
item->Destroy(); item->Destroy();
} }
else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) && else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) &&
item->IsKindOf(RUNTIME_CLASS(AAmmo))) item->IsKindOf(PClass::FindActor(NAME_Ammo)))
{ {
if (defitem == NULL) if (defitem == NULL)
{ {
@ -1367,21 +1362,22 @@ void APlayerPawn::GiveDefaultInventory ()
// it provides player class based protection that should not affect // it provides player class based protection that should not affect
// any other protection item. // any other protection item.
PClassPlayerPawn *myclass = GetClass(); PClassPlayerPawn *myclass = GetClass();
GiveInventoryType(RUNTIME_CLASS(AHexenArmor)); GiveInventoryType(PClass::FindActor(NAME_HexenArmor));
AHexenArmor *harmor = FindInventory<AHexenArmor>(); auto harmor = FindInventory(NAME_HexenArmor);
harmor->Slots[4] = myclass->HexenArmor[0];
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr);
Slots[4] = myclass->HexenArmor[0];
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
harmor->SlotsIncrement[i] = myclass->HexenArmor[i + 1]; SlotsIncrement[i] = myclass->HexenArmor[i + 1];
} }
// BasicArmor must come right after that. It should not affect any // BasicArmor must come right after that. It should not affect any
// other protection item as well but needs to process the damage // other protection item as well but needs to process the damage
// before the HexenArmor does. // before the HexenArmor does.
ABasicArmor *barmor = Spawn<ABasicArmor> (); auto barmor = (AInventory*)Spawn(NAME_BasicArmor);
barmor->BecomeItem (); barmor->BecomeItem ();
barmor->SavePercent = 0;
barmor->Amount = 0;
AddInventory (barmor); AddInventory (barmor);
// Now add the items from the DECORATE definition // Now add the items from the DECORATE definition
@ -1701,13 +1697,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream)
DEFINE_ACTION_FUNCTION(AActor, A_SkullPop) DEFINE_ACTION_FUNCTION(AActor, A_SkullPop)
{ {
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS_DEF(spawntype, APlayerChunk); PARAM_CLASS_DEF(spawntype, APlayerPawn);
APlayerPawn *mo; APlayerPawn *mo;
player_t *player; player_t *player;
// [GRB] Parameterized version // [GRB] Parameterized version
if (spawntype == NULL || !spawntype->IsDescendantOf(RUNTIME_CLASS(APlayerChunk))) if (spawntype == NULL || !spawntype->IsDescendantOf(PClass::FindActor("PlayerChunk")))
{ {
spawntype = dyn_cast<PClassPlayerPawn>(PClass::FindClass("BloodySkull")); spawntype = dyn_cast<PClassPlayerPawn>(PClass::FindClass("BloodySkull"));
if (spawntype == NULL) if (spawntype == NULL)
@ -2205,7 +2201,7 @@ void P_DeathThink (player_t *player)
player->TickPSprites(); player->TickPSprites();
player->onground = (player->mo->Z() <= player->mo->floorz); player->onground = (player->mo->Z() <= player->mo->floorz);
if (player->mo->IsKindOf (RUNTIME_CLASS(APlayerChunk))) if (player->mo->IsKindOf (PClass::FindActor("PlayerChunk")))
{ // Flying bloody skull or flying ice chunk { // Flying bloody skull or flying ice chunk
player->viewheight = 6; player->viewheight = 6;
player->deltaviewheight = 0; player->deltaviewheight = 0;

View file

@ -56,7 +56,7 @@
#include "m_argv.h" #include "m_argv.h"
#include "p_local.h" #include "p_local.h"
#include "doomerrors.h" #include "doomerrors.h"
#include "a_weaponpiece.h" #include "a_weapons.h"
#include "p_conversation.h" #include "p_conversation.h"
#include "v_text.h" #include "v_text.h"
#include "thingdef.h" #include "thingdef.h"

View file

@ -46,7 +46,6 @@
#include "templates.h" #include "templates.h"
#include "r_defs.h" #include "r_defs.h"
#include "a_pickups.h" #include "a_pickups.h"
#include "a_armor.h"
#include "s_sound.h" #include "s_sound.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "p_lnspec.h" #include "p_lnspec.h"
@ -67,9 +66,7 @@
#include "teaminfo.h" #include "teaminfo.h"
#include "v_video.h" #include "v_video.h"
#include "r_data/colormaps.h" #include "r_data/colormaps.h"
#include "a_weaponpiece.h"
#include "vmbuilder.h" #include "vmbuilder.h"
#include "a_ammo.h"
#include "a_keys.h" #include "a_keys.h"
#include "g_levellocals.h" #include "g_levellocals.h"
@ -98,9 +95,9 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool
} }
return static_cast<PClassActor *>(cls); return static_cast<PClassActor *>(cls);
} }
static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false) static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false)
{ {
return static_cast<AAmmo::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AAmmo), optional)); return static_cast<PClassInventory *>(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional));
} }
static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false) static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false)
{ {
@ -465,23 +462,6 @@ static bool PointerCheck(PType *symtype, PType *checktype)
return symptype != nullptr && checkptype != nullptr && symptype->ClassRestriction->IsDescendantOf(checkptype->ClassRestriction); return symptype != nullptr && checkptype != nullptr && symptype->ClassRestriction->IsDescendantOf(checkptype->ClassRestriction);
} }
static void *ScriptVar(DObject *obj, PClass *cls, FName field, PType *type)
{
auto sym = dyn_cast<PField>(cls->Symbols.FindSymbol(field, true));
if (sym && (sym->Type == type || PointerCheck(sym->Type, type)))
{
return (((char*)obj) + sym->Offset);
}
I_Error("Variable %s of type %s not found in %s\n", field.GetChars(), type->DescriptiveName(), cls->TypeName.GetChars());
return nullptr;
}
template<class T>
T &TypedScriptVar(DObject *obj, PClass *cls, FName field, PType *type)
{
return *(T*)ScriptVar(obj, cls, field, type);
}
//========================================================================== //==========================================================================
// //
// Info Property handlers // Info Property handlers
@ -1742,149 +1722,6 @@ DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory)
} }
} }
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(backpackamount, I, Ammo)
{
PROP_INT_PARM(i, 0);
defaults->BackpackAmount = i;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(backpackmaxamount, I, Ammo)
{
PROP_INT_PARM(i, 0);
defaults->BackpackMaxAmount = i;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(dropamount, I, Ammo)
{
PROP_INT_PARM(i, 0);
defaults->DropAmount = i;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(armor, maxsaveamount, I, BasicArmorBonus)
{
PROP_INT_PARM(i, 0);
defaults->MaxSaveAmount = i;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(armor, maxbonus, I, BasicArmorBonus)
{
PROP_INT_PARM(i, 0);
defaults->BonusCount = i;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(armor, maxbonusmax, I, BasicArmorBonus)
{
PROP_INT_PARM(i, 0);
defaults->BonusMax = i;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(saveamount, I, Armor)
{
PROP_INT_PARM(i, 0);
// Special case here because this property has to work for 2 unrelated classes
if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
{
((ABasicArmorPickup*)defaults)->SaveAmount=i;
}
else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
{
((ABasicArmorBonus*)defaults)->SaveAmount=i;
}
else
{
I_Error("\"Armor.SaveAmount\" requires an actor of type \"Armor\"");
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(savepercent, F, Armor)
{
PROP_DOUBLE_PARM(i, 0);
i = clamp(i, 0., 100.)/100.;
// Special case here because this property has to work for 2 unrelated classes
if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
{
((ABasicArmorPickup*)defaults)->SavePercent = i;
}
else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
{
((ABasicArmorBonus*)defaults)->SavePercent = i;
}
else
{
I_Error("\"Armor.SavePercent\" requires an actor of type \"Armor\"\n");
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(maxabsorb, I, Armor)
{
PROP_INT_PARM(i, 0);
// Special case here because this property has to work for 2 unrelated classes
if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
{
((ABasicArmorPickup*)defaults)->MaxAbsorb = i;
}
else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
{
((ABasicArmorBonus*)defaults)->MaxAbsorb = i;
}
else
{
I_Error("\"Armor.MaxAbsorb\" requires an actor of type \"Armor\"\n");
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(maxfullabsorb, I, Armor)
{
PROP_INT_PARM(i, 0);
// Special case here because this property has to work for 2 unrelated classes
if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
{
((ABasicArmorPickup*)defaults)->MaxFullAbsorb = i;
}
else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
{
((ABasicArmorBonus*)defaults)->MaxFullAbsorb = i;
}
else
{
I_Error("\"Armor.MaxFullAbsorb\" requires an actor of type \"Armor\"\n");
}
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================
@ -2251,24 +2088,6 @@ DEFINE_CLASS_PROPERTY(preferredskin, S, Weapon)
// NoOp - only for Skulltag compatibility // NoOp - only for Skulltag compatibility
} }
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(number, I, WeaponPiece)
{
PROP_INT_PARM(i, 0);
defaults->PieceValue = 1 << (i-1);
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(weapon, S, WeaponPiece)
{
PROP_STRING_PARM(str, 0);
defaults->WeaponClass = FindClassTentativeWeapon(str);
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================
@ -2429,7 +2248,7 @@ DEFINE_SCRIPTED_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
I_Error("Unknown powerup type %s", str); I_Error("Unknown powerup type %s", str);
} }
} }
TypedScriptVar<PClassActor*>(defaults, info, NAME_PowerupType, NewClassPointer(RUNTIME_CLASS(AActor))) = cls; defaults->PointerVar<PClassActor>(NAME_PowerupType) = cls;
} }
//========================================================================== //==========================================================================
@ -3018,7 +2837,7 @@ DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile)
DEFINE_SCRIPTED_PROPERTY(playerclass, S, PowerMorph) DEFINE_SCRIPTED_PROPERTY(playerclass, S, PowerMorph)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_PlayerClass, NewClassPointer(RUNTIME_CLASS(APlayerPawn))) = FindClassTentativePlayerPawn(str, bag.fromDecorate); defaults->PointerVar<PClassActor>(NAME_PlayerClass) = FindClassTentativePlayerPawn(str, bag.fromDecorate);
} }
//========================================================================== //==========================================================================
@ -3027,7 +2846,7 @@ DEFINE_SCRIPTED_PROPERTY(playerclass, S, PowerMorph)
DEFINE_SCRIPTED_PROPERTY(morphstyle, M, PowerMorph) DEFINE_SCRIPTED_PROPERTY(morphstyle, M, PowerMorph)
{ {
PROP_INT_PARM(i, 0); PROP_INT_PARM(i, 0);
TypedScriptVar<int>(defaults, bag.Info, NAME_MorphStyle, TypeSInt32) = i; defaults->IntVar(NAME_MorphStyle) = i;
} }
//========================================================================== //==========================================================================
@ -3036,7 +2855,7 @@ DEFINE_SCRIPTED_PROPERTY(morphstyle, M, PowerMorph)
DEFINE_SCRIPTED_PROPERTY(morphflash, S, PowerMorph) DEFINE_SCRIPTED_PROPERTY(morphflash, S, PowerMorph)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_MorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); defaults->PointerVar<PClassActor>(NAME_MorphFlash) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
} }
//========================================================================== //==========================================================================
@ -3045,7 +2864,7 @@ DEFINE_SCRIPTED_PROPERTY(morphflash, S, PowerMorph)
DEFINE_SCRIPTED_PROPERTY(unmorphflash, S, PowerMorph) DEFINE_SCRIPTED_PROPERTY(unmorphflash, S, PowerMorph)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_UnMorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); defaults->PointerVar<PClassActor>(NAME_UnMorphFlash) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
} }

View file

@ -1380,6 +1380,13 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Proper
TArray<PField *> fields; TArray<PField *> fields;
ZCC_Identifier *id = (ZCC_Identifier *)p->Body; ZCC_Identifier *id = (ZCC_Identifier *)p->Body;
if (FName(p->NodeName) == FName("prefix") && Wads.GetLumpFile(Lump) == 0)
{
// only for internal definitions: Allow setting a prefix. This is only for compatiblity with the old DECORATE property parser, but not for general use.
prefix = id->Id;
}
else
{
do do
{ {
auto f = dyn_cast<PField>(type->Symbols.FindSymbol(id->Id, true)); auto f = dyn_cast<PField>(type->Symbols.FindSymbol(id->Id, true));
@ -1390,6 +1397,7 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Proper
fields.Push(f); fields.Push(f);
id = (ZCC_Identifier*)id->SiblingNext; id = (ZCC_Identifier*)id->SiblingNext;
} while (id != p->Body); } while (id != p->Body);
}
FString qualifiedname; FString qualifiedname;
// Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen.

View file

@ -9,6 +9,7 @@
#include "zscript/inventory/inventory.txt" #include "zscript/inventory/inventory.txt"
#include "zscript/inventory/inv_misc.txt" #include "zscript/inventory/inv_misc.txt"
#include "zscript/inventory/weapons.txt" #include "zscript/inventory/weapons.txt"
#include "zscript/inventory/weaponpiece.txt"
#include "zscript/inventory/armor.txt" #include "zscript/inventory/armor.txt"
#include "zscript/inventory/ammo.txt" #include "zscript/inventory/ammo.txt"
#include "zscript/inventory/health.txt" #include "zscript/inventory/health.txt"

View file

@ -42,11 +42,18 @@ struct Console native
native static void HideConsole(); native static void HideConsole();
} }
struct DamageTypeDefinition native
{
native static bool IgnoreArmor(Name type);
}
struct GameInfoStruct native struct GameInfoStruct native
{ {
// will be extended as needed. // will be extended as needed.
native Name backpacktype; native Name backpacktype;
native double Armor2Percent; native double Armor2Percent;
native String ArmorIcon1;
native String ArmorIcon2;
} }
class Object native class Object native

View file

@ -4,7 +4,7 @@
** **
**--------------------------------------------------------------------------- **---------------------------------------------------------------------------
** Copyright 2000-2016 Randy Heit ** Copyright 2000-2016 Randy Heit
** Copyright 2006-2017 Cheistoph Oelckers ** Copyright 2006-2017 Christoph Oelckers
** All rights reserved. ** All rights reserved.
** **
** Redistribution and use in source and binary forms, with or without ** Redistribution and use in source and binary forms, with or without
@ -33,10 +33,15 @@
** **
*/ */
class Ammo : Inventory native class Ammo : Inventory
{ {
native int BackpackAmount; int BackpackAmount;
native int BackpackMaxAmount; int BackpackMaxAmount;
/*meta*/ int DropAmount;
property BackpackAmount: BackpackAmount;
property BackpackMaxAmount: BackpackMaxAmount;
property DropAmount: DropAmount;
Default Default
{ {
@ -44,7 +49,33 @@ class Ammo : Inventory native
Inventory.PickupSound "misc/ammo_pkup"; Inventory.PickupSound "misc/ammo_pkup";
} }
native Class<Actor> GetParentAmmo (); //===========================================================================
//
// AAmmo :: GetParentAmmo
//
// Returns the least-derived ammo type that this ammo is a descendant of.
// That is, if this ammo is an immediate subclass of Ammo, then this ammo's
// type is returned. If this ammo's superclass is not Ammo, then this
// function travels up the inheritance chain until it finds a type that is
// an immediate subclass of Ammo and returns that.
//
// The intent of this is that all unique ammo types will be immediate
// subclasses of Ammo. To make different pickups with different ammo amounts,
// you subclass the type of ammo you want a different amount for and edit
// that.
//
//===========================================================================
Class<Ammo> GetParentAmmo ()
{
class<Object> type = GetClass();
while (type.GetParentClass() != "Ammo" && type.GetParentClass() != NULL)
{
type = type.GetParentClass();
}
return (class<Ammo>)(type);
}
//=========================================================================== //===========================================================================
// //
@ -113,7 +144,7 @@ class Ammo : Inventory native
} }
let type = GetParentAmmo(); let type = GetParentAmmo();
if (GetClass() == type) if (GetClass() != type && type != null)
{ {
if (!GoAway ()) if (!GoAway ())
{ {

View file

@ -1,4 +1,39 @@
class Armor : Inventory native /*
** armor.txt
** Implements all variations of armor objects
**
**---------------------------------------------------------------------------
** Copyright 2002-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.
**---------------------------------------------------------------------------
**
*/
class Armor : Inventory
{ {
Default Default
{ {
@ -6,32 +41,209 @@ class Armor : Inventory native
} }
} }
class BasicArmor : Armor native //===========================================================================
//
//
// BasicArmor
//
// Basic armor absorbs a specific percent of the damage. You should
// never pickup a BasicArmor. Instead, you pickup a BasicArmorPickup
// or BasicArmorBonus and those gives you BasicArmor when it activates.
//
//
//===========================================================================
class BasicArmor : Armor
{ {
native int AbsorbCount; int AbsorbCount;
native double SavePercent; double SavePercent;
native int MaxAbsorb; int MaxAbsorb;
native int MaxFullAbsorb; int MaxFullAbsorb;
native int BonusCount; int BonusCount;
native Name ArmorType; Name ArmorType;
native int ActualSaveAmount; int ActualSaveAmount;
Default Default
{ {
Inventory.Amount 0;
+Inventory.KEEPDEPLETED +Inventory.KEEPDEPLETED
} }
//===========================================================================
//
// ABasicArmor :: Tick
//
// If BasicArmor is given to the player by means other than a
// BasicArmorPickup, then it may not have an icon set. Fix that here.
//
//===========================================================================
override void Tick ()
{
Super.Tick ();
AbsorbCount = 0;
if (!Icon.isValid())
{
String icontex = gameinfo.ArmorIcon1;
if (SavePercent >= gameinfo.Armor2Percent && gameinfo.ArmorIcon2.Length() != 0)
icontex = gameinfo.ArmorIcon2;
if (icontex.Length() != 0)
Icon = TexMan.CheckForTexture (icontex, TexMan.TYPE_Any);
}
} }
class BasicArmorBonus : Armor native //===========================================================================
//
// ABasicArmor :: CreateCopy
//
//===========================================================================
override Inventory CreateCopy (Actor other)
{ {
native double SavePercent; // The default, for when you don't already have armor // BasicArmor that is in use is stored in the inventory as BasicArmor.
native int MaxSaveAmount; // BasicArmor that is in reserve is not.
native int MaxAbsorb; let copy = BasicArmor(Spawn("BasicArmor"));
native int MaxFullAbsorb; copy.SavePercent = SavePercent != 0 ? SavePercent : 0.33335; // slightly more than 1/3 to avoid roundoff errors.
native int SaveAmount; copy.Amount = Amount;
native int BonusCount; copy.MaxAmount = MaxAmount;
native int BonusMax; copy.Icon = Icon;
copy.BonusCount = BonusCount;
copy.ArmorType = ArmorType;
copy.ActualSaveAmount = ActualSaveAmount;
GoAwayAndDie ();
return copy;
}
//===========================================================================
//
// ABasicArmor :: HandlePickup
//
//===========================================================================
override bool HandlePickup (Inventory item)
{
if (item.GetClass() == "BasicArmor")
{
// You shouldn't be picking up BasicArmor anyway.
return true;
}
if (!item.bIgnoreSkill)
{
if (item is "BasicArmorBonus")
{
let armor = BasicArmorBonus(item);
armor.SaveAmount = int(armor.SaveAmount * G_SkillPropertyFloat(SKILLP_ArmorFactor));
}
else if (item is "BasicArmorPickup")
{
let armor = BasicArmorPickup(item);
armor.SaveAmount = int(armor.SaveAmount * G_SkillPropertyFloat(SKILLP_ArmorFactor));
}
}
return false;
}
//===========================================================================
//
// ABasicArmor :: AbsorbDamage
//
//===========================================================================
override void AbsorbDamage (int damage, Name damageType, out int newdamage)
{
int saved;
if (!DamageTypeDefinition.IgnoreArmor(damageType))
{
int full = MAX(0, MaxFullAbsorb - AbsorbCount);
if (damage < full)
{
saved = damage;
}
else
{
saved = full + int((damage - full) * SavePercent);
if (MaxAbsorb > 0 && saved + AbsorbCount > MaxAbsorb)
{
saved = MAX(0, MaxAbsorb - AbsorbCount);
}
}
if (Amount < saved)
{
saved = Amount;
}
newdamage -= saved;
Amount -= saved;
AbsorbCount += saved;
if (Amount == 0)
{
// The armor has become useless
SavePercent = 0;
ArmorType = 'None'; // Not NAME_BasicArmor.
// Now see if the player has some more armor in their inventory
// and use it if so. As in Strife, the best armor is used up first.
BasicArmorPickup best = null;
Inventory probe = Owner.Inv;
while (probe != null)
{
let inInv = BasicArmorPickup(probe);
if (inInv != null)
{
if (best == null || best.SavePercent < inInv.SavePercent)
{
best = inInv;
}
}
probe = probe.Inv;
}
if (best != null)
{
Owner.UseInventory (best);
}
}
damage = newdamage;
}
// Once the armor has absorbed its part of the damage, then apply its damage factor, if any, to the player
if ((damage > 0) && (ArmorType != 'None')) // BasicArmor is not going to have any damage factor, so skip it.
{
ApplyDamageFactors(ArmorType, damageType, damage, damage);
}
}
}
//===========================================================================
//
//
// BasicArmorBonus
//
//
//===========================================================================
class BasicArmorBonus : Armor
{
double SavePercent; // The default, for when you don't already have armor
int MaxSaveAmount;
int MaxAbsorb;
int MaxFullAbsorb;
int SaveAmount;
int BonusCount;
int BonusMax;
property prefix: Armor;
property MaxSaveAmount: MaxSaveAmount;
property SaveAmount : SaveAmount;
property SavePercent: SavePercent;
property MaxAbsorb: MaxAbsorb;
property MaxFullAbsorb: MaxFullAbsorb;
property MaxBonus: BonusCount;
property MaxBonusMax: BonusMax;
Default Default
{ {
@ -40,33 +252,365 @@ class BasicArmorBonus : Armor native
Inventory.MaxAmount 0; Inventory.MaxAmount 0;
Armor.SavePercent 33.335; Armor.SavePercent 33.335;
} }
//===========================================================================
//
// ABasicArmorBonus :: CreateCopy
//
//===========================================================================
override Inventory CreateCopy (Actor other)
{
let copy = BasicArmorBonus(Super.CreateCopy (other));
if (!bIgnoreSkill)
{
SaveAmount = int(SaveAmount * G_SkillPropertyFloat(SKILLP_ArmorFactor));
} }
class BasicArmorPickup : Armor native copy.SavePercent = SavePercent;
copy.SaveAmount = SaveAmount;
copy.MaxSaveAmount = MaxSaveAmount;
copy.BonusCount = BonusCount;
copy.BonusMax = BonusMax;
copy.MaxAbsorb = MaxAbsorb;
copy.MaxFullAbsorb = MaxFullAbsorb;
return copy;
}
//===========================================================================
//
// ABasicArmorBonus :: Use
//
// Tries to add to the amount of BasicArmor a player has.
//
//===========================================================================
override bool Use (bool pickup)
{
let armor = BasicArmor(Owner.FindInventory("BasicArmor"));
bool result = false;
// This should really never happen but let's be prepared for a broken inventory.
if (armor == null)
{
armor = BasicArmor(Spawn("BasicArmor"));
armor.BecomeItem ();
armor.Amount = 0;
armor.MaxAmount = MaxSaveAmount;
Owner.AddInventory (armor);
}
if (BonusCount > 0 && armor.BonusCount < BonusMax)
{
armor.BonusCount = min(armor.BonusCount + BonusCount, BonusMax);
result = true;
}
int saveAmount = min(SaveAmount, MaxSaveAmount);
if (saveAmount <= 0)
{ // If it can't give you anything, it's as good as used.
return BonusCount > 0 ? result : true;
}
// If you already have more armor than this item can give you, you can't
// use it.
if (armor.Amount >= MaxSaveAmount + armor.BonusCount)
{
return result;
}
if (armor.Amount <= 0)
{ // Should never be less than 0, but might as well check anyway
armor.Amount = 0;
armor.Icon = Icon;
armor.SavePercent = clamp(SavePercent, 0, 100) / 100;
armor.MaxAbsorb = MaxAbsorb;
armor.ArmorType = GetClassName();
armor.MaxFullAbsorb = MaxFullAbsorb;
armor.ActualSaveAmount = MaxSaveAmount;
}
armor.Amount = min(armor.Amount + saveAmount, MaxSaveAmount + armor.BonusCount);
armor.MaxAmount = max(armor.MaxAmount, MaxSaveAmount);
return true;
}
}
//===========================================================================
//
//
// BasicArmorPickup
//
//
//===========================================================================
class BasicArmorPickup : Armor
{ {
native double SavePercent; double SavePercent;
native int MaxAbsorb; int MaxAbsorb;
native int MaxFullAbsorb; int MaxFullAbsorb;
native int SaveAmount; int SaveAmount;
property prefix: Armor;
property SaveAmount : SaveAmount;
property SavePercent: SavePercent;
property MaxAbsorb: MaxAbsorb;
property MaxFullAbsorb: MaxFullAbsorb;
Default Default
{ {
+Inventory.AUTOACTIVATE; +Inventory.AUTOACTIVATE;
Inventory.MaxAmount 0; Inventory.MaxAmount 0;
} }
//===========================================================================
//
// ABasicArmorPickup :: CreateCopy
//
//===========================================================================
override Inventory CreateCopy (Actor other)
{
let copy = BasicArmorPickup(Super.CreateCopy (other));
if (!bIgnoreSkill)
{
SaveAmount = int(SaveAmount * G_SkillPropertyFloat(SKILLP_ArmorFactor));
} }
class HexenArmor : Armor native copy.SavePercent = SavePercent;
copy.SaveAmount = SaveAmount;
copy.MaxAbsorb = MaxAbsorb;
copy.MaxFullAbsorb = MaxFullAbsorb;
return copy;
}
//===========================================================================
//
// ABasicArmorPickup :: Use
//
// Either gives you new armor or replaces the armor you already have (if
// the SaveAmount is greater than the amount of armor you own). When the
// item is auto-activated, it will only be activated if its max amount is 0
// or if you have no armor active already.
//
//===========================================================================
override bool Use (bool pickup)
{
let armor = BasicArmor(Owner.FindInventory("BasicArmor"));
// This should really never happen but let's be prepared for a broken inventory.
if (armor == null)
{
armor = BasicArmor(Spawn("BasicArmor"));
armor.BecomeItem ();
Owner.AddInventory (armor);
}
else
{
// If you already have more armor than this item gives you, you can't
// use it.
if (armor.Amount >= SaveAmount + armor.BonusCount)
{
return false;
}
// Don't use it if you're picking it up and already have some.
if (pickup && armor.Amount > 0 && MaxAmount > 0)
{
return false;
}
}
armor.SavePercent = clamp(SavePercent, 0, 100) / 100;
armor.Amount = SaveAmount + armor.BonusCount;
armor.MaxAmount = SaveAmount;
armor.Icon = Icon;
armor.MaxAbsorb = MaxAbsorb;
armor.MaxFullAbsorb = MaxFullAbsorb;
armor.ArmorType = GetClassName();
armor.ActualSaveAmount = SaveAmount;
return true;
}
}
//===========================================================================
//
//
// HexenArmor
//
// Hexen armor consists of four separate armor types plus a conceptual armor
// type (the player himself) that work together as a single armor.
//
//
//===========================================================================
class HexenArmor : Armor
{ {
native double Slots[5]; double Slots[5];
native double SlotsIncrement[4]; double SlotsIncrement[4];
Default Default
{ {
+Inventory.KEEPDEPLETED +Inventory.KEEPDEPLETED
+Inventory.UNDROPPABLE +Inventory.UNTOSSABLE
}
//===========================================================================
//
// AHexenArmor :: CreateCopy
//
//===========================================================================
override Inventory CreateCopy (Actor other)
{
// Like BasicArmor, HexenArmor is used in the inventory but not the map.
// health is the slot this armor occupies.
// Amount is the quantity to give (0 = normal max).
let copy = HexenArmor(Spawn("HexenArmor"));
copy.AddArmorToSlot (health, Amount);
GoAwayAndDie ();
return copy;
}
//===========================================================================
//
// AHexenArmor :: CreateTossable
//
// Since this isn't really a single item, you can't drop it. Ever.
//
//===========================================================================
override Inventory CreateTossable ()
{
return NULL;
}
//===========================================================================
//
// AHexenArmor :: HandlePickup
//
//===========================================================================
override bool HandlePickup (Inventory item)
{
if (item is "HexenArmor")
{
if (AddArmorToSlot (item.health, item.Amount))
{
item.bPickupGood = true;
}
return true;
}
return false;
}
//===========================================================================
//
// AHexenArmor :: AddArmorToSlot
//
//===========================================================================
protected bool AddArmorToSlot (int slot, int amount)
{
double hits;
if (slot < 0 || slot > 3)
{
return false;
}
if (amount <= 0)
{
hits = SlotsIncrement[slot];
if (Slots[slot] < hits)
{
Slots[slot] = hits;
return true;
}
}
else
{
hits = amount * 5;
let total = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
let max = SlotsIncrement[0] + SlotsIncrement[1] + SlotsIncrement[2] + SlotsIncrement[3] + Slots[4] + 4 * 5;
if (total < max)
{
Slots[slot] += hits;
return true;
}
}
return false;
}
//===========================================================================
//
// AHexenArmor :: AbsorbDamage
//
//===========================================================================
override void AbsorbDamage (int damage, Name damageType, out int newdamage)
{
if (!DamageTypeDefinition.IgnoreArmor(damageType))
{
double savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
if (savedPercent)
{ // armor absorbed some damage
if (savedPercent > 100)
{
savedPercent = 100;
}
for (int i = 0; i < 4; i++)
{
if (Slots[i])
{
// 300 damage always wipes out the armor unless some was added
// with the dragon skin bracers.
if (damage < 10000)
{
Slots[i] -= damage * SlotsIncrement[i] / 300.;
if (Slots[i] < 2)
{
Slots[i] = 0;
}
}
else
{
Slots[i] = 0;
}
}
}
int saved = int(damage * savedPercent / 100.);
if (saved > savedPercent*2)
{
saved = int(savedPercent*2);
}
newdamage -= saved;
damage = newdamage;
}
}
}
//===========================================================================
//
// AHexenArmor :: DepleteOrDestroy
//
//===========================================================================
override void DepleteOrDestroy()
{
for (int i = 0; i < 4; i++)
{
Slots[i] = 0;
}
} }
} }

View file

@ -28,10 +28,8 @@ class ScoreItem : Inventory
// //
//=========================================================================== //===========================================================================
class Key : Inventory native class Key : Inventory
{ {
native uint8 KeyNumber;
Default Default
{ {
+DONTGIB; // Don't disappear due to a crusher +DONTGIB; // Don't disappear due to a crusher

View file

@ -47,44 +47,12 @@ class Inventory : Actor native
virtual native bool DrawPowerup(int x, int y); virtual native bool DrawPowerup(int x, int y);
virtual native void AbsorbDamage (int damage, Name damageType, out int newdamage); virtual native void AbsorbDamage (int damage, Name damageType, out int newdamage);
//=========================================================================== native bool DoRespawn();
//
// AInventory :: Travelled
//
// Called when an item in somebody's inventory is carried over to another
// map, in case it needs to do special reinitialization.
//
//===========================================================================
virtual void Travelled() {}
//===========================================================================
//
// AInventory :: DoEffect
//
// Handles any effect an item might apply to its owner
// Normally only used by subclasses of Powerup
//
//===========================================================================
virtual void DoEffect() {}
virtual double GetSpeedFactor() { return 1; }
virtual bool GetNoTeleportFreeze() { return false; }
virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {}
virtual void AlterWeaponSprite(VisStyle vis, in out int changed) {}
virtual void OwnerDied() {}
native bool GoAway(); native bool GoAway();
native void GoAwayAndDie(); native void GoAwayAndDie();
native void BecomeItem(); native void BecomeItem();
native void BecomePickup(); native void BecomePickup();
// These are regular functions for the item itself.
private native void A_RestoreSpecialDoomThing();
private native void A_RestoreSpecialThing1();
private native void A_RestoreSpecialThing2();
// In this case the caller function is more than a simple wrapper around the virtual method and // In this case the caller function is more than a simple wrapper around the virtual method and
// is what must be actually called to pick up an item. // is what must be actually called to pick up an item.
virtual protected native bool TryPickup(in out Actor toucher); virtual protected native bool TryPickup(in out Actor toucher);
@ -112,6 +80,118 @@ class Inventory : Actor native
TNT1 A 1; TNT1 A 1;
Stop; Stop;
} }
// These are regular functions for the item itself.
//---------------------------------------------------------------------------
//
// PROC A_RestoreSpecialThing1
//
// Make a special thing visible again.
//
//---------------------------------------------------------------------------
void A_RestoreSpecialThing1()
{
bInvisible = false;
if (DoRespawn ())
{
A_PlaySound ("misc/spawn", CHAN_VOICE);
}
}
//---------------------------------------------------------------------------
//
// PROC A_RestoreSpecialThing2
//
//---------------------------------------------------------------------------
void A_RestoreSpecialThing2()
{
bSpecial = true;
if (!Default.bNoGravity)
{
bNoGravity = false;
}
SetState (SpawnState);
}
//---------------------------------------------------------------------------
//
// PROC A_RestoreSpecialDoomThing
//
//---------------------------------------------------------------------------
void A_RestoreSpecialDoomThing()
{
bInvisible = false;
bSpecial = true;
if (!Default.bNoGravity)
{
bNoGravity = false;
}
if (DoRespawn ())
{
SetState (SpawnState);
A_PlaySound ("misc/spawn", CHAN_VOICE);
Spawn ("ItemFog", Pos, ALLOW_REPLACE);
}
}
//===========================================================================
//
// AInventory :: DepleteOrDestroy
//
// If the item is depleted, just change its amount to 0, otherwise it's destroyed.
//
//===========================================================================
virtual void DepleteOrDestroy ()
{
// If it's not ammo or an internal armor, destroy it.
// Ammo needs to stick around, even when it's zero for the benefit
// of the weapons that use it and to maintain the maximum ammo
// amounts a backpack might have given.
// Armor shouldn't be removed because they only work properly when
// they are the last items in the inventory.
if (bKeepDepleted)
{
Amount = 0;
}
else
{
Destroy();
}
}
//===========================================================================
//
// AInventory :: Travelled
//
// Called when an item in somebody's inventory is carried over to another
// map, in case it needs to do special reinitialization.
//
//===========================================================================
virtual void Travelled() {}
//===========================================================================
//
// AInventory :: DoEffect
//
// Handles any effect an item might apply to its owner
// Normally only used by subclasses of Powerup
//
//===========================================================================
virtual void DoEffect() {}
virtual double GetSpeedFactor() { return 1; }
virtual bool GetNoTeleportFreeze() { return false; }
virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {}
virtual void AlterWeaponSprite(VisStyle vis, in out int changed) {}
virtual void OwnerDied() {}
} }
class StateProvider : Inventory native class StateProvider : Inventory native

View file

@ -0,0 +1,225 @@
/*
** a_weaponpieces.cpp
** Implements generic weapon pieces
**
**---------------------------------------------------------------------------
** Copyright 2006-2016 Cheistoph Oelckers
** Copyright 2006-2016 Randy Heit
** 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.
**---------------------------------------------------------------------------
**
*/
class WeaponHolder : Inventory
{
int PieceMask;
Class<Weapon> PieceWeapon;
Default
{
+NOBLOCKMAP
+NOSECTOR
+INVENTORY.UNDROPPABLE
}
}
class WeaponPiece : Inventory
{
Default
{
+WEAPONSPAWN;
}
int PieceValue;
Class<Weapon> WeaponClass;
Weapon FullWeapon;
property number: PieceValue;
property weapon: WeaponClass;
//==========================================================================
//
// TryPickupWeaponPiece
//
//==========================================================================
override bool TryPickupRestricted (in out Actor toucher)
{
// Wrong class, but try to pick up for ammo
if (ShouldStay())
{ // Can't pick up weapons for other classes in coop netplay
return false;
}
let Defaults = GetDefaultByType(WeaponClass);
bool gaveSome = !!(toucher.GiveAmmo (Defaults.AmmoType1, Defaults.AmmoGive1) +
toucher.GiveAmmo (Defaults.AmmoType2, Defaults.AmmoGive2));
if (gaveSome)
{
GoAwayAndDie ();
}
return gaveSome;
}
//==========================================================================
//
// TryPickupWeaponPiece
//
//==========================================================================
override bool TryPickup (in out Actor toucher)
{
Inventory item;
WeaponHolder hold = NULL;
bool shouldStay = ShouldStay ();
int gaveAmmo;
let Defaults = GetDefaultByType(WeaponClass);
FullWeapon = NULL;
for(item=toucher.Inv; item; item=item.Inv)
{
hold = WeaponHolder(item);
if (hold != null)
{
if (hold.PieceWeapon == WeaponClass)
{
break;
}
hold = NULL;
}
}
if (!hold)
{
hold = WeaponHolder(Spawn("WeaponHolder"));
hold.BecomeItem();
hold.AttachToOwner(toucher);
hold.PieceMask = 0;
hold.PieceWeapon = WeaponClass;
}
int pieceval = 1 << (PieceValue - 1);
if (shouldStay)
{
// Cooperative net-game
if (hold.PieceMask & pieceval)
{
// Already has the piece
return false;
}
toucher.GiveAmmo (Defaults.AmmoType1, Defaults.AmmoGive1);
toucher.GiveAmmo (Defaults.AmmoType2, Defaults.AmmoGive2);
}
else
{ // Deathmatch or singleplayer game
gaveAmmo = toucher.GiveAmmo (Defaults.AmmoType1, Defaults.AmmoGive1) +
toucher.GiveAmmo (Defaults.AmmoType2, Defaults.AmmoGive2);
if (hold.PieceMask & pieceval)
{
// Already has the piece, check if mana needed
if (!gaveAmmo) return false;
GoAwayAndDie();
return true;
}
}
hold.PieceMask |= pieceval;
// Check if weapon assembled
if (hold.PieceMask == (1 << Defaults.health) - 1)
{
if (!toucher.FindInventory (WeaponClass))
{
FullWeapon= Weapon(Spawn(WeaponClass));
// The weapon itself should not give more ammo to the player.
FullWeapon.AmmoGive1 = 0;
FullWeapon.AmmoGive2 = 0;
FullWeapon.AttachToOwner(toucher);
FullWeapon.AmmoGive1 = Defaults.AmmoGive1;
FullWeapon.AmmoGive2 = Defaults.AmmoGive2;
}
}
GoAwayAndDie();
return true;
}
//===========================================================================
//
//
//
//===========================================================================
override bool ShouldStay ()
{
// We want a weapon piece to behave like a weapon, so follow the exact
// same logic as weapons when deciding whether or not to stay.
return (((multiplayer &&
(!deathmatch && !alwaysapplydmflags)) || sv_weaponstay) && !bDropped);
}
//===========================================================================
//
// PickupMessage
//
// Returns the message to print when this actor is picked up.
//
//===========================================================================
override String PickupMessage ()
{
if (FullWeapon)
{
return FullWeapon.PickupMessage();
}
else
{
return Super.PickupMessage();
}
}
//===========================================================================
//
// DoPlayPickupSound
//
// Plays a sound when this actor is picked up.
//
//===========================================================================
override void PlayPickupSound (Actor toucher)
{
if (FullWeapon)
{
FullWeapon.PlayPickupSound(toucher);
}
else
{
Super.PlayPickupSound(toucher);
}
}
}

View file

@ -104,27 +104,6 @@ class WeaponGiver : Weapon native
} }
} }
class WeaponHolder : Inventory native
{
native int PieceMask;
native Class<Actor> PieceWeapon;
Default
{
+NOBLOCKMAP
+NOSECTOR
+INVENTORY.UNDROPPABLE
}
}
class WeaponPiece : Inventory native
{
Default
{
+WEAPONSPAWN;
}
}
struct WeaponSlots native struct WeaponSlots native
{ {
native bool, int, int LocateWeapon(class<Weapon> weap); native bool, int, int LocateWeapon(class<Weapon> weap);

View file

@ -1,5 +1,28 @@
class DynamicLight : Actor native class DynamicLight : Actor native
{ {
enum EArgs
{
LIGHT_RED = 0,
LIGHT_GREEN = 1,
LIGHT_BLUE = 2,
LIGHT_INTENSITY = 3,
LIGHT_SECONDARY_INTENSITY = 4,
LIGHT_SCALE = 3,
};
enum ELightType
{
PointLight,
PulseLight,
FlickerLight,
RandomFlickerLight,
SectorLight,
SpotLight,
ColorPulseLight,
ColorFlickerLight,
RandomColorFlickerLight
};
Default Default
{ {
Height 0; Height 0;
@ -136,29 +159,6 @@ class PointLightFlickerRandomSubtractive : PointLightFlickerRandom
} }
} }
class VavoomLight : DynamicLight native
{
Default
{
}
}
class VavoomLightWhite : VavoomLight native
{
Default
{
}
}
class VavoomLightColor : VavoomLight native
{
Default
{
}
}
class PointLightAttenuated : PointLight class PointLightAttenuated : PointLight
{ {
Default Default
@ -199,3 +199,45 @@ class PointLightFlickerRandomAttenuated :PointLightFlickerRandom
} }
} }
class VavoomLight : DynamicLight
{
Default
{
DynamicLight.Type "Point";
}
override void BeginPlay ()
{
if (CurSector) AddZ(-CurSector.floorplane.ZatPoint(pos.XY), false); // z is absolute for Vavoom lights
Super.BeginPlay();
}
}
class VavoomLightWhite : VavoomLight
{
override void BeginPlay ()
{
args[LIGHT_INTENSITY] = args[0] * 4;
args[LIGHT_RED] = 128;
args[LIGHT_GREEN] = 128;
args[LIGHT_BLUE] = 128;
Super.BeginPlay();
}
}
class VavoomLightColor : VavoomLight
{
override void BeginPlay ()
{
int radius = args[0] * 4;
args[LIGHT_RED] = args[1] >> 1;
args[LIGHT_GREEN] = args[2] >> 1;
args[LIGHT_BLUE] = args[3] >> 1;
args[LIGHT_INTENSITY] = radius;
Super.BeginPlay();
}
}

View file

@ -138,7 +138,7 @@ class PlayerPawn : Actor native
native void CheckWeaponSwitch(class<Inventory> item); native void CheckWeaponSwitch(class<Inventory> item);
} }
class PlayerChunk : PlayerPawn native class PlayerChunk : PlayerPawn
{ {
Default Default
{ {

View file

@ -157,8 +157,8 @@ extend class PlayerPawn
{ {
if (AllActorClasses[i] is "Key") if (AllActorClasses[i] is "Key")
{ {
readonly<Key> keyitem = GetDefaultByType ((class<Key>)(AllActorClasses[i])); let keyitem = GetDefaultByType (AllActorClasses[i]);
if (keyitem.KeyNumber != 0) if (keyitem.special1 != 0)
{ {
let item = Inventory(Spawn(AllActorClasses[i])); let item = Inventory(Spawn(AllActorClasses[i]));
if (!item.CallTryPickup (self)) if (!item.CallTryPickup (self))