diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5d1b8f76b..e37e655be 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1195,11 +1195,9 @@ set (PCH_SOURCES w_wad.cpp wi_stuff.cpp zstrformat.cpp - g_inventory/a_ammo.cpp g_inventory/a_armor.cpp g_inventory/a_keys.cpp g_inventory/a_pickups.cpp - g_inventory/a_weaponpiece.cpp g_inventory/a_weapons.cpp g_strife/strife_sbar.cpp g_shared/a_action.cpp diff --git a/src/actor.h b/src/actor.h index e1cc56290..9f6d00e02 100644 --- a/src/actor.h +++ b/src/actor.h @@ -721,7 +721,7 @@ public: // Finds the first item of a particular type. AInventory *FindInventory (PClassActor *type, bool subclass=false); - AInventory *FindInventory (FName type); + AInventory *FindInventory (FName type, bool subclass = false); template T *FindInventory () { return static_cast (FindInventory (RUNTIME_TEMPLATE_CLASS(T))); diff --git a/src/am_map.cpp b/src/am_map.cpp index 29fdcf682..cb7595ab6 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2740,8 +2740,8 @@ void AM_drawKeys () mpoint_t p; DAngle angle; - TThinkerIterator it; - AKey *key; + TThinkerIterator it(NAME_Key); + AInventory *key; while ((key = it.Next()) != NULL) { @@ -2853,7 +2853,7 @@ void AM_drawThings () // Find the key's own color. // Only works correctly if single-key locks have lower numbers than any-key locks. // 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)) { @@ -2863,7 +2863,7 @@ void AM_drawThings () else if (am_showkeys) { int P_GetMapColorForKey (AInventory * key); - int c = P_GetMapColorForKey(static_cast(t)); + int c = P_GetMapColorForKey(static_cast(t)); if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c)); else color = AMColors[AMColors.ThingColor_CountItem]; @@ -3048,7 +3048,7 @@ void AM_Drawer () return; 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) { diff --git a/src/b_think.cpp b/src/b_think.cpp index 1501a03ac..7ce276aa0 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -21,7 +21,6 @@ #include "d_event.h" #include "d_player.h" #include "vectors.h" -#include "a_ammo.h" 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 (item); - PClassActor *parent = ammo->GetParentAmmo (); - AInventory *holdingammo = player->mo->FindInventory (parent); - + auto ac = PClass::FindActor(NAME_Ammo); + auto parent = item->GetClass(); + while (parent->ParentClass != ac) parent = (PClassActor*)(parent->ParentClass); + AInventory *holdingammo = player->mo->FindInventory(parent); if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount) { return; diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index 0a92a58b9..971c94a38 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -31,7 +31,6 @@ #include "templates.h" #include "d_net.h" #include "d_event.h" -#include "a_armor.h" #define QUEUESIZE 128 #define MESSAGESIZE 128 @@ -434,7 +433,7 @@ static bool DoSubstitution (FString &out, const char *in) { if (strnicmp(a, "armor", 5) == 0) { - AInventory *armor = player->mo->FindInventory(); + AInventory *armor = player->mo->FindInventory(NAME_BasicArmor); out.AppendFormat("%d", armor != NULL ? armor->Amount : 0); } } diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 1239d71bb..85d10de02 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -74,8 +74,6 @@ #include "info.h" #include "v_text.h" #include "vmbuilder.h" -#include "a_armor.h" -#include "a_ammo.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO @@ -1536,7 +1534,7 @@ static int PatchSprite (int sprNum) static int PatchAmmo (int ammoNum) { PClassActor *ammoType = NULL; - AAmmo *defaultAmmo = NULL; + AInventory *defaultAmmo = NULL; int result; int oldclip; int dummy; @@ -1549,7 +1547,7 @@ static int PatchAmmo (int ammoNum) ammoType = AmmoNames[ammoNum]; if (ammoType != NULL) { - defaultAmmo = (AAmmo *)GetDefaultByType (ammoType); + defaultAmmo = (AInventory*)GetDefaultByType (ammoType); if (defaultAmmo != NULL) { max = &defaultAmmo->MaxAmount; @@ -1575,8 +1573,8 @@ static int PatchAmmo (int ammoNum) // Calculate the new backpack-given amounts for this ammo. if (ammoType != NULL) { - defaultAmmo->BackpackMaxAmount = defaultAmmo->MaxAmount * 2; - defaultAmmo->BackpackAmount = defaultAmmo->Amount; + defaultAmmo->IntVar("BackpackMaxAmount") = defaultAmmo->MaxAmount * 2; + defaultAmmo->IntVar("BackpackAmount") = defaultAmmo->Amount; } // 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)) { - defaultAmmo = (AAmmo *)GetDefaultByType (type); + defaultAmmo = (AInventory *)GetDefaultByType (type); defaultAmmo->MaxAmount = *max; defaultAmmo->Amount = Scale (defaultAmmo->Amount, *per, oldclip); } @@ -1673,7 +1671,7 @@ static int PatchWeapon (int weapNum) info->AmmoType1 = (PClassInventory*)AmmoNames[val]; if (info->AmmoType1 != NULL) { - info->AmmoGive1 = ((AAmmo*)GetDefaultByType (info->AmmoType1))->Amount * 2; + info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2; if (info->AmmoUse1 == 0) { info->AmmoUse1 = 1; @@ -1949,26 +1947,24 @@ static int PatchMisc (int dummy) // Update default item properties by patching the affected items // Note: This won't have any effect on DECORATE derivates of these items! - ABasicArmorPickup *armor; - armor = static_cast (GetDefaultByName ("GreenArmor")); + auto armor = GetDefaultByName ("GreenArmor"); if (armor!=NULL) { - armor->SaveAmount = 100 * deh.GreenAC; - armor->SavePercent = deh.GreenAC == 1 ? 0.33335 : 0.5; + armor->IntVar(NAME_SaveAmount) = 100 * deh.GreenAC; + armor->FloatVar(NAME_SavePercent) = deh.GreenAC == 1 ? 0.33335 : 0.5; } - armor = static_cast (GetDefaultByName ("BlueArmor")); + armor = GetDefaultByName ("BlueArmor"); if (armor!=NULL) { - armor->SaveAmount = 100 * deh.BlueAC; - armor->SavePercent = deh.BlueAC == 1 ? 0.33335 : 0.5; + armor->IntVar(NAME_SaveAmount) = 100 * deh.BlueAC; + armor->FloatVar(NAME_SavePercent) = deh.BlueAC == 1 ? 0.33335 : 0.5; } - ABasicArmorBonus *barmor; - barmor = static_cast (GetDefaultByName ("ArmorBonus")); + auto barmor = GetDefaultByName ("ArmorBonus"); if (barmor!=NULL) { - barmor->MaxSaveAmount = deh.MaxArmor; + barmor->IntVar("MaxSaveAmount") = deh.MaxArmor; } AInventory *health; @@ -2930,7 +2926,7 @@ static bool LoadDehSupp () else { 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); } @@ -3184,7 +3180,7 @@ bool ADehackedPickup::ShouldRespawn () void ADehackedPickup::PlayPickupSound (AActor *toucher) { if (RealPickup != nullptr) - RealPickup->PlayPickupSound (toucher); + RealPickup->CallPlayPickupSound (toucher); } void ADehackedPickup::DoPickupSpecial (AActor *toucher) diff --git a/src/d_player.h b/src/d_player.h index e4db7336f..05facd9fe 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -177,11 +177,6 @@ public: }; -class APlayerChunk : public APlayerPawn -{ - DECLARE_CLASS (APlayerChunk, APlayerPawn) -}; - // // PlayerPawn flags // diff --git a/src/dobject.cpp b/src/dobject.cpp index e31a3dd23..10b37f636 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -571,7 +571,7 @@ DEFINE_ACTION_FUNCTION(DObject, GetClassName) void *DObject::ScriptVar(FName field, PType *type) { auto sym = dyn_cast(GetClass()->Symbols.FindSymbol(field, true)); - if (sym && sym->Type == type) + if (sym && (sym->Type == type || type == nullptr)) { return (((char*)this) + sym->Offset); } diff --git a/src/dobject.h b/src/dobject.h index 367350427..2f907d493 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -482,6 +482,7 @@ public: PalEntry &ColorVar(FName field); FName &NameVar(FName field); double &FloatVar(FName field); + template T*& PointerVar(FName field); // If you need to replace one object with another and want to // change any pointers from the old object to the new object, diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b135c1b65..2d41a57e3 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -45,7 +45,6 @@ #include "autosegs.h" #include "v_text.h" #include "a_pickups.h" -#include "a_weaponpiece.h" #include "d_player.h" #include "doomerrors.h" #include "fragglescript/t_fs.h" diff --git a/src/dobjtype.h b/src/dobjtype.h index ee5d0984e..12245795a 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -1093,5 +1093,9 @@ inline double &DObject::FloatVar(FName field) return *(double*)ScriptVar(field, TypeFloat64); } - +template +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 diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 7c5adb6bc..d3746a49e 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -69,7 +69,6 @@ #include "p_setup.h" #include "p_spec.h" #include "r_utility.h" -#include "a_ammo.h" #include "math/cmath.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 // 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. - if (item->GetClass()->ParentClass != RUNTIME_CLASS(AAmmo)) - { - item->Destroy (); - } - else - { - item->Amount = 0; - } + item->DepleteOrDestroy(); } } } @@ -2628,7 +2620,7 @@ void FParser::SF_MaxPlayerAmmo() if(amount < 0) amount = 0; if (!iammo) { - iammo = static_cast(Spawn (ammotype)); + iammo = static_cast(Spawn (ammotype)); iammo->Amount = 0; iammo->AttachToOwner (players[playernum].mo); } @@ -2644,13 +2636,13 @@ void FParser::SF_MaxPlayerAmmo() break; } } - ((AAmmo*)iammo)->BackpackMaxAmount=amount; + iammo->IntVar("BackpackMaxAmount") = amount; } t_return.type = svt_int; AInventory * iammo = players[playernum].mo->FindInventory(ammotype); 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; } } diff --git a/src/g_game.cpp b/src/g_game.cpp index c98eee244..936caea18 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -447,7 +447,7 @@ CCMD (use) { 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) { - SendItemDrop = who->FindInventory(PClass::FindActor(argv[1])); + SendItemDrop = who->FindInventory(argv[1]); } } @@ -513,7 +513,7 @@ CCMD (select) { if (argv.argc() > 1) { - AInventory *item = who->FindInventory(PClass::FindActor(argv[1])); + AInventory *item = who->FindInventory(argv[1]); if (item != NULL) { who->InvSel = item; diff --git a/src/g_inventory/a_ammo.cpp b/src/g_inventory/a_ammo.cpp deleted file mode 100644 index b1765e1e4..000000000 --- a/src/g_inventory/a_ammo.cpp +++ /dev/null @@ -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(type); -} - -DEFINE_ACTION_FUNCTION(AAmmo, GetParentAmmo) -{ - PARAM_SELF_PROLOGUE(AAmmo); - ACTION_RETURN_OBJECT(self->GetParentAmmo()); -} diff --git a/src/g_inventory/a_ammo.h b/src/g_inventory/a_ammo.h deleted file mode 100644 index 445f44a34..000000000 --- a/src/g_inventory/a_ammo.h +++ /dev/null @@ -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; -}; - diff --git a/src/g_inventory/a_armor.cpp b/src/g_inventory/a_armor.cpp deleted file mode 100644 index 8bb32c921..000000000 --- a/src/g_inventory/a_armor.cpp +++ /dev/null @@ -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 - -#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 (); - 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(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(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(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 (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 (); - - if (armor == NULL) - { - armor = Spawn (); - 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 (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 (); - bool result = false; - - if (armor == NULL) - { - armor = Spawn (); - 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 (); - 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(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; - } -} \ No newline at end of file diff --git a/src/g_inventory/a_armor.h b/src/g_inventory/a_armor.h deleted file mode 100644 index 63febda91..000000000 --- a/src/g_inventory/a_armor.h +++ /dev/null @@ -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); -}; - diff --git a/src/g_inventory/a_keys.cpp b/src/g_inventory/a_keys.cpp index 31237018c..0ad6b72f1 100644 --- a/src/g_inventory/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -51,7 +51,6 @@ // //=========================================================================== - //=========================================================================== // // @@ -64,29 +63,24 @@ struct OneKey bool check(AActor *owner) { - if (owner->IsKindOf(RUNTIME_CLASS(AKey))) - { - // P_GetMapColorForKey() checks the key directly - return owner->IsA(key) || owner->GetSpecies() == key->TypeName; - } - else - { - // Other calls check an actor that may have a key in its inventory. - AInventory *item; + // P_GetMapColorForKey() checks the key directly + if (owner->IsA(key) || owner->GetSpecies() == key->TypeName) return true; - for (item = owner->Inventory; item != NULL; item = item->Inventory) + // Other calls check an actor that may have a key in its inventory. + AInventory *item; + + for (item = owner->Inventory; item != NULL; item = item->Inventory) + { + if (item->IsA(key)) { - if (item->IsA(key)) - { - return true; - } - else if (item->GetSpecies() == key->TypeName) - { - return true; - } + return true; + } + else if (item->GetSpecies() == key->TypeName) + { + return true; } - return false; } + return false; } }; @@ -138,9 +132,10 @@ struct Lock // An empty key list means that any key will do if (!keylist.Size()) { + auto kt = PClass::FindActor(NAME_Key); for (AInventory * item = owner->Inventory; item != NULL; item = item->Inventory) { - if (item->IsKindOf (RUNTIME_CLASS(AKey))) + if (item->IsKindOf (kt)) { return true; } @@ -192,12 +187,12 @@ static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc) keygroup->anykeylist.Push (k); //... but only keys get key numbers! - if (mi->IsDescendantOf(RUNTIME_CLASS(AKey))) + if (mi->IsDescendantOf(PClass::FindActor(NAME_Key))) { if (!ignorekey && - static_cast(GetDefaultByType(mi))->KeyNumber == 0) + GetDefaultByType(mi)->special1 == 0) { - static_cast(GetDefaultByType(mi))->KeyNumber=++currentnumber; + GetDefaultByType(mi)->special1 = ++currentnumber; } } } @@ -387,14 +382,15 @@ static void ParseLock(FScanner &sc) static void ClearLocks() { unsigned int i; + auto kt = PClass::FindActor(NAME_Key); 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(GetDefaultByType(PClassActor::AllActorClasses[i])); + auto key = GetDefaultByType(PClassActor::AllActorClasses[i]); if (key != NULL) { - key->KeyNumber = 0; + key->special1 = 0; } } } @@ -523,15 +519,6 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote) return false; } -//========================================================================== -// -// AKey implementation -// -//========================================================================== - -IMPLEMENT_CLASS(AKey, false, false) -DEFINE_FIELD(AKey, KeyNumber) - //========================================================================== // // These functions can be used to get color information for diff --git a/src/g_inventory/a_keys.h b/src/g_inventory/a_keys.h index a62670413..328ff04a6 100644 --- a/src/g_inventory/a_keys.h +++ b/src/g_inventory/a_keys.h @@ -1,14 +1,8 @@ #ifndef A_KEYS_H #define A_KEYS_H -#include "a_pickups.h" - -class AKey : public AInventory -{ - DECLARE_CLASS (AKey, AInventory) -public: - BYTE KeyNumber; -}; +class AActor; +class AInventory; bool P_CheckKeys (AActor *owner, int keynum, bool remote); void P_InitKeyMessages (); diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index b19fcf1f2..2a7f0b3bf 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -20,7 +20,6 @@ #include "p_spec.h" #include "serializer.h" #include "virtual.h" -#include "a_ammo.h" #include "c_functions.h" #include "g_levellocals.h" @@ -80,71 +79,6 @@ void PClassInventory::Finalize(FStateDefinitions &statedef) ((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; FString AInventory::StaticLastMessage; @@ -908,7 +842,7 @@ void AInventory::Touch (AActor *toucher) // real player to make noise. if (player != NULL) { - PlayPickupSound (player->mo); + CallPlayPickupSound (player->mo); if (!(ItemFlags & IF_NOSCREENFLASH)) { player->bonuscount = BONUSADD; @@ -916,7 +850,7 @@ void AInventory::Touch (AActor *toucher) } else { - PlayPickupSound (toucher); + CallPlayPickupSound (toucher); } } @@ -1117,19 +1051,10 @@ void AInventory::OnDestroy () void AInventory::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 (ItemFlags & IF_KEEPDEPLETED) + IFVIRTUAL(AInventory, DepleteOrDestroy) { - Amount = 0; - } - else - { - Destroy(); + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } } @@ -1273,6 +1198,11 @@ bool AInventory::DoRespawn () 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; GoAwayAndDie (); } - else if (MaxAmount == 0 && !IsKindOf(RUNTIME_CLASS(AAmmo))) - { - // 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 + else if (MaxAmount > 0) { // Add the item to the inventory. It is not already there, or HandlePickup // 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; } diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 3ef2fd285..4ad0e66b8 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -82,7 +82,7 @@ public: // virtual methods that only get overridden by special internal classes, like DehackedPickup. // There is no need to expose these to scripts. - virtual void DepleteOrDestroy (); + void DepleteOrDestroy (); virtual bool ShouldRespawn (); virtual void DoPickupSpecial (AActor *toucher); diff --git a/src/g_inventory/a_weaponpiece.cpp b/src/g_inventory/a_weaponpiece.cpp deleted file mode 100644 index 2fe14ae91..000000000 --- a/src/g_inventory/a_weaponpiece.cpp +++ /dev/null @@ -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(inv); - - if (hold->PieceWeapon==WeaponClass) break; - hold=NULL; - } - } - if (!hold) - { - hold=static_cast(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<health)-1) - { - if (!toucher->FindInventory (WeaponClass)) - { - FullWeapon= static_cast(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); - } -} - diff --git a/src/g_inventory/a_weaponpiece.h b/src/g_inventory/a_weaponpiece.h deleted file mode 100644 index ca5ed6a06..000000000 --- a/src/g_inventory/a_weaponpiece.h +++ /dev/null @@ -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 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; -}; diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 242181ced..1b7745979 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -54,7 +54,7 @@ #include "serializer.h" #include "thingdef.h" #include "virtual.h" -#include "a_ammo.h" + #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) { @@ -518,10 +518,10 @@ AAmmo *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount) { amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); } - ammo = static_cast(other->FindInventory (ammotype)); + ammo = other->FindInventory (ammotype); if (ammo == NULL) { - ammo = static_cast(Spawn (ammotype)); + ammo = static_cast(Spawn (ammotype)); ammo->Amount = MIN (amount, ammo->MaxAmount); ammo->AttachToOwner (other); } @@ -545,7 +545,7 @@ AAmmo *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount) //=========================================================================== 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)) { diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 55354c139..ed18df421 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -1,7 +1,6 @@ #pragma once -#include "a_ammo.h" - +#include "a_pickups.h" class PClassWeapon; class AWeapon; @@ -126,7 +125,7 @@ public: float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. // In-inventory instance variables - TObjPtr Ammo1, Ammo2; + TObjPtr Ammo1, Ammo2; TObjPtr SisterWeapon; float FOVScale; int Crosshair; // 0 to use player's crosshair @@ -182,8 +181,8 @@ public: }; protected: - AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount); - bool AddExistingAmmo (AAmmo *ammo, int amount); + AInventory *AddAmmo (AActor *other, PClassActor *ammotype, int amount); + bool AddExistingAmmo (AInventory *ammo, int amount); AWeapon *AddWeapon (PClassWeapon *weapon); }; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index a1db0a15a..68309d8cc 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -13,7 +13,6 @@ #include "serializer.h" #include "p_enemy.h" #include "d_player.h" -#include "a_armor.h" #include "r_data/sprites.h" #include "g_levellocals.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; ) { AInventory *next = item->Inventory; - if (item->IsKindOf (RUNTIME_CLASS(AArmor))) + if (item->IsKindOf (PClass::FindActor(NAME_Armor))) { item->DepleteOrDestroy(); } @@ -364,10 +363,11 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } pmo->Destroy (); // Restore playerclass armor to its normal amount. - AHexenArmor *hxarmor = mo->FindInventory(); + auto hxarmor = mo->FindInventory(NAME_HexenArmor); 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; } diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index d681eebad..414d2a730 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -294,7 +294,6 @@ int FindMugShotStateIndex(FName state); // Base Status Bar ---------------------------------------------------------- class FTexture; -class AAmmo; enum { @@ -395,7 +394,7 @@ protected: 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: AInventory *ValidateInvFirst (int numVisible) const; diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 5ba0b62b8..05494522e 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -45,20 +45,17 @@ #include "st_stuff.h" #include "m_swap.h" #include "a_keys.h" -#include "a_armor.h" #include "templates.h" #include "i_system.h" #include "sbarinfo.h" #include "gi.h" #include "r_data/r_translate.h" -#include "a_weaponpiece.h" #include "g_level.h" #include "v_palette.h" #include "p_acs.h" #include "gstrings.h" #include "version.h" #include "cmdlib.h" -#include "a_ammo.h" #include "g_levellocals.h" #define ARTIFLASH_OFFSET (statusBar->invBarOffset+6) @@ -1069,7 +1066,7 @@ public: //prepare ammo counts GetCurrentAmmo(ammo1, ammo2, ammocount1, ammocount2); - armor = CPlayer->mo->FindInventory(); + armor = CPlayer->mo->FindInventory(NAME_BasicArmor); if(state != HUD_AltHud) { @@ -1517,9 +1514,9 @@ public: return translationtables[TRANSLATION_Players][int(CPlayer - players)]; } - AAmmo *ammo1, *ammo2; + AInventory *ammo1, *ammo2; int ammocount1, ammocount2; - ABasicArmor *armor; + AInventory *armor; FImageCollection Images; unsigned int invBarOffset; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 4cb587bc9..8cb90a350 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -244,31 +244,31 @@ class CommandDrawImage : public SBarInfoCommandFlowControl texture = TexMan(statusBar->CPlayer->mo->ScoreIcon); else if(type == AMMO1) { - AAmmo *ammo = statusBar->ammo1; + auto ammo = statusBar->ammo1; if(ammo != NULL) GetIcon(ammo); } else if(type == AMMO2) { - AAmmo *ammo = statusBar->ammo2; + auto ammo = statusBar->ammo2; if(ammo != NULL) GetIcon(ammo); } else if(type == ARMOR) { - ABasicArmor *armor = statusBar->armor; + auto armor = statusBar->armor; if(armor != NULL && armor->Amount != 0) GetIcon(armor); } else if(type == WEAPONICON) { - AWeapon *weapon = statusBar->CPlayer->ReadyWeapon; + auto weapon = statusBar->CPlayer->ReadyWeapon; if(weapon != NULL) GetIcon(weapon); } 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) texture = TexMan(item->Icon); } @@ -276,13 +276,15 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { int armorType = type - HEXENARMOR_ARMOR; - AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory(); + auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor); 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 - alpha *= MIN(1., harmor->Slots[armorType] / harmor->SlotsIncrement[armorType]); + alpha *= MIN(1., Slots[armorType] / SlotsIncrement[armorType]); texture = statusBar->Images[image]; } else @@ -416,10 +418,10 @@ class CommandDrawSwitchableImage : public CommandDrawImage for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *cls = PClassActor::AllActorClasses[i]; - if (cls->IsDescendantOf(RUNTIME_CLASS(AKey))) + if (cls->IsDescendantOf(PClass::FindActor(NAME_Key))) { - AKey *key = (AKey *)GetDefaultByType(cls); - if (key->KeyNumber == keynum) + auto key = GetDefaultByType(cls); + if (key->special1 == keynum) return cls->TypeName; } } @@ -554,9 +556,9 @@ class CommandDrawSwitchableImage : public CommandDrawImage 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(item)->KeyNumber; + int keynum = item->special1; if(keynum) { if(keynum == conditionalValue[0]) @@ -592,11 +594,11 @@ class CommandDrawSwitchableImage : public CommandDrawImage } else if(condition == ARMORTYPE) { - ABasicArmor *armor = (ABasicArmor *) statusBar->CPlayer->mo->FindInventory(NAME_BasicArmor); + auto armor = statusBar->CPlayer->mo->FindInventory(NAME_BasicArmor); if(armor != NULL) { - bool matches1 = armor->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 matches1 = armor->NameVar(NAME_ArmorType).GetIndex() == armorType[0] && EvaluateOperation(conditionalOperator[0], conditionalValue[0], armor->Amount); + bool matches2 = armor->NameVar(NAME_ArmorType).GetIndex() == armorType[1] && EvaluateOperation(conditionalOperator[1], conditionalValue[1], armor->Amount); drawAlt = 1; if(conditionAnd) @@ -614,12 +616,12 @@ class CommandDrawSwitchableImage : public CommandDrawImage } 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)) drawAlt = 1; 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); if((item != NULL && secondCondition) && drawAlt == 0) //both { @@ -1076,10 +1078,10 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); 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); - inventoryItem = RUNTIME_CLASS(AAmmo); + inventoryItem = PClass::FindActor(NAME_Ammo); } if(parenthesized) sc.MustGetToken(')'); @@ -1092,10 +1094,10 @@ class CommandDrawNumber : public CommandDrawString if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); 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); - inventoryItem = RUNTIME_CLASS(AAmmo); + inventoryItem = PClass::FindActor(NAME_Ammo); } if(parenthesized) sc.MustGetToken(')'); @@ -1409,16 +1411,16 @@ class CommandDrawNumber : public CommandDrawString case SAVEPERCENT: { double add = 0; - AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory(); + auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor); if(harmor != NULL) { - add = harmor->Slots[0] + harmor->Slots[1] + - harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]; + double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr); + add = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4]; } //Hexen counts basic armor also so we should too. if(statusBar->armor != NULL) { - add += statusBar->armor->SavePercent * 100; + add += statusBar->armor->FloatVar(NAME_SavePercent) * 100; } if(value == ARMORCLASS) add /= 5; @@ -1435,7 +1437,7 @@ class CommandDrawNumber : public CommandDrawString { // num = statusBar.CPlayer.mo.GetEffectTicsForItem(inventoryItem) / TICRATE + 1; static VMFunction *func = nullptr; - if (func == nullptr) func = static_cast(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 }; int retv; VMReturn ret(&retv); @@ -1474,7 +1476,7 @@ class CommandDrawNumber : public CommandDrawString num = 0; 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++; } break; @@ -2429,7 +2431,7 @@ class CommandDrawKeyBar : public SBarInfoCommand int rowWidth = 0; 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; if(item == NULL) @@ -2630,10 +2632,10 @@ class CommandDrawBar : public SBarInfoCommand sc.MustGetToken(TK_Identifier); type = AMMO; 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); - data.inventoryItem = RUNTIME_CLASS(AAmmo); + data.inventoryItem = PClass::FindActor(NAME_Ammo); } if(parenthesized) sc.MustGetToken(')'); @@ -2825,8 +2827,10 @@ class CommandDrawBar : public SBarInfoCommand break; case POWERUPTIME: { + // [value, max] = statusBar.CPlayer.mo.GetEffectTicsForItem(inventoryItem); + // value++; max++; static VMFunction *func = nullptr; - if (func == nullptr) func = static_cast(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 }; VMReturn ret[2]; int ival; @@ -2840,16 +2844,17 @@ class CommandDrawBar : public SBarInfoCommand case SAVEPERCENT: { double add = 0; - AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory(); - if(harmor != NULL) + auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor); + if (harmor != NULL) { - add = harmor->Slots[0] + harmor->Slots[1] + - harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]; + double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr); + add = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4]; } + //Hexen counts basic armor also so we should too. if(statusBar->armor != NULL) { - add += statusBar->armor->SavePercent * 100; + add += statusBar->armor->FloatVar(NAME_SavePercent) * 100; } value = int(add); max = 100; @@ -3143,12 +3148,12 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl 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(inv); - if(hold->PieceWeapon == weapon) + if(inv->PointerVar("PieceWeapon") == weapon) { - SetTruth(0 != (hold->PieceMask & (1 << (piece-1))), block, statusBar); + SetTruth(0 != (inv->IntVar("PieceMask") & (1 << (piece-1))), block, statusBar); return; } } @@ -3312,10 +3317,10 @@ class CommandWeaponAmmo : public SBarInfoNegatableFlowControl for(int i = 0;i < 2;i++) { 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); - ammo[i] = RUNTIME_CLASS(AAmmo); + ammo[i] = PClass::FindActor(NAME_Ammo); } if(sc.CheckToken(TK_OrOr)) @@ -3689,3 +3694,5 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc) sc.MustGetToken('}'); return NULL; } + + diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 839582d34..37312748c 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -43,8 +43,6 @@ #include "c_cvars.h" #include "w_wad.h" #include "a_keys.h" -#include "a_armor.h" -#include "a_ammo.h" #include "sbar.h" #include "sc_man.h" #include "templates.h" @@ -298,7 +296,7 @@ static void DrawHealth(player_t *CPlayer, int x, int y) const bool haveBerserk = hud_berserk_health && nullptr != berserkpic - && nullptr != CPlayer->mo->FindInventory(PClass::FindActor(NAME_PowerStrength)); + && nullptr != CPlayer->mo->FindInventory(NAME_PowerStrength); DrawImageToBox(haveBerserk ? berserkpic : healthpic, x, y, 31, 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 bestslot = 4; 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); if (ac) @@ -327,7 +326,7 @@ static void DrawArmor(ABasicArmor * barmor, AHexenArmor * harmor, int x, int y) bestslot = 0; for (int i = 1; i < 4; ++i) { - if (harmor->Slots[i] > harmor->Slots[bestslot]) + if (Slots[i] > Slots[bestslot]) { bestslot = i; } @@ -386,9 +385,9 @@ static TArray KeyTypes, UnassignedKeyTypes; static int ktcmp(const void * a, const void * b) { - AKey *key1 = (AKey*)GetDefaultByType ( *(PClassActor **)a ); - AKey *key2 = (AKey*)GetDefaultByType ( *(PClassActor **)b ); - return key1->KeyNumber - key2->KeyNumber; + auto key1 = GetDefaultByType ( *(PClassActor **)a ); + auto key2 = GetDefaultByType ( *(PClassActor **)b ); + return key1->special1 - key2->special1; } static void SetKeyTypes() @@ -396,13 +395,14 @@ static void SetKeyTypes() for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); 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(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); } @@ -419,8 +419,7 @@ static void SetKeyTypes() else { // Don't leave the list empty - PClassActor *ti = RUNTIME_CLASS(AKey); - KeyTypes.Push(ti); + KeyTypes.Push(PClass::FindActor(NAME_Key)); } } @@ -527,7 +526,7 @@ static void AddAmmoToList(AWeapon * weapdef) PClassInventory * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; if (ti) { - AAmmo * ammodef=(AAmmo*)GetDefaultByType(ti); + auto ammodef=(AInventory*)GetDefaultByType(ti); if (ammodef && !(ammodef->ItemFlags&IF_INVBAR)) { @@ -561,9 +560,9 @@ static void GetAmmoTextLengths(player_t *CPlayer, int& ammocur, int& ammomax) { for (auto type : orderedammos) { - AAmmo * ammoitem = static_cast(CPlayer->mo->FindInventory(type)); - AAmmo * inv = nullptr == ammoitem - ? static_cast(GetDefaultByType(type)) + auto ammoitem = CPlayer->mo->FindInventory(type); + auto inv = nullptr == ammoitem + ? static_cast(GetDefaultByType(type)) : ammoitem; assert(nullptr != inv); @@ -648,9 +647,9 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) { 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 icon = !AltIcon.isNull()? AltIcon : inv->Icon; if (!icon.isValid()) continue; @@ -1142,8 +1141,7 @@ void DrawHUD() DrawFrags(CPlayer, 5, hudheight-70); } DrawHealth(CPlayer, 5, hudheight-45); - DrawArmor(CPlayer->mo->FindInventory(), - CPlayer->mo->FindInventory(), 5, hudheight-20); + DrawArmor(CPlayer->mo->FindInventory(NAME_BasicArmor), CPlayer->mo->FindInventory(NAME_HexenArmor), 5, hudheight-20); i=DrawKeys(CPlayer, hudwidth-4, hudheight-10); i=DrawAmmo(CPlayer, hudwidth-5, i); if (hud_showweapons) DrawWeapons(CPlayer, hudwidth - 5, i); diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 6a790f845..f8ed4a94b 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -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) { diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index 110bcfbe9..5b4f8d68e 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -12,8 +12,6 @@ #include "m_swap.h" #include "templates.h" #include "a_keys.h" -#include "a_armor.h" -#include "a_ammo.h" #include "gi.h" #include "g_level.h" #include "colormatcher.h" @@ -257,7 +255,7 @@ public: item != NULL; item = item->Inventory) { - if (item->IsKindOf (RUNTIME_CLASS(AKey))) + if (item->IsKindOf (PClass::FindActor(NAME_Key))) { if (i == KeyPopPos) { @@ -404,7 +402,7 @@ private: DrawImage (&HealthBar, 49, 7); // Armor - item = CPlayer->mo->FindInventory(); + item = CPlayer->mo->FindInventory(NAME_BasicArmor); if (item != NULL && item->Amount > 0) { DrawImage (TexMan(item->Icon), 2, 9); @@ -412,7 +410,7 @@ private: } // Ammo - AAmmo *ammo1, *ammo2; + AInventory *ammo1, *ammo2; int ammocount1, ammocount2; GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2); @@ -432,7 +430,7 @@ private: } // Sigil - item = CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil)); + item = CPlayer->mo->FindInventory(NAME_Sigil); if (item != NULL) { DrawImage (TexMan(item->Icon), 253, 7); @@ -469,7 +467,7 @@ private: TAG_DONE); // Draw armor - ABasicArmor *armor = CPlayer->mo->FindInventory(); + auto armor = CPlayer->mo->FindInventory(NAME_BasicArmor); if (armor != NULL && armor->Amount != 0) { DrINumberOuter (armor->Amount, 35, -10, false, 7); @@ -480,7 +478,7 @@ private: } // Draw ammo - AAmmo *ammo1, *ammo2; + AInventory *ammo1, *ammo2; int ammocount1, ammocount2; GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2); @@ -629,7 +627,7 @@ private: i < endpos && item != NULL; item = item->Inventory) { - if (!item->IsKindOf (RUNTIME_CLASS(AKey))) + if (!item->IsKindOf (PClass::FindActor(NAME_Key))) continue; if (i < pos) @@ -674,7 +672,7 @@ private: item != NULL; item = item->Inventory) { - if (item->IsKindOf (RUNTIME_CLASS(AKey))) + if (item->IsKindOf (PClass::FindActor(NAME_Key))) { i++; } diff --git a/src/gi.cpp b/src/gi.cpp index a13804aad..6c7349592 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -47,6 +47,8 @@ gameinfo_t gameinfo; DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype) 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] = diff --git a/src/gl/dynlights/a_dynlight.cpp b/src/gl/dynlights/a_dynlight.cpp index ceeca70db..acc23d955 100644 --- a/src/gl/dynlights/a_dynlight.cpp +++ b/src/gl/dynlights/a_dynlight.cpp @@ -109,49 +109,6 @@ DEFINE_CLASS_PROPERTY(type, S, DynamicLight) // //========================================================================== 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; @@ -173,8 +130,7 @@ void ADynamicLight::Serialize(FSerializer &arc) arc("lightflags", lightflags, def->lightflags) ("lighttype", lighttype, def->lighttype) ("tickcount", m_tickCount, def->m_tickCount) - ("currentradius", m_currentRadius, def->m_currentRadius) - .Array("lightradius", m_Radius, def->m_Radius, 2); + ("currentradius", m_currentRadius, def->m_currentRadius); if (lighttype == PulseLight) arc("lastupdate", m_lastUpdate, def->m_lastUpdate) @@ -201,15 +157,13 @@ void ADynamicLight::BeginPlay() //Super::BeginPlay(); ChangeStatNum(STAT_DLIGHT); - m_Radius[0] = args[LIGHT_INTENSITY]; - m_Radius[1] = args[LIGHT_SECONDARY_INTENSITY]; specialf1 = DAngle(double(SpawnAngle)).Normalized360().Degrees; visibletoplayer = true; if (gl.legacyMode && (flags4 & MF4_ATTENUATE)) { - m_Radius[0] = m_Radius[0] * 2 / 3; - m_Radius[1] = m_Radius[1] * 2 / 3; + args[LIGHT_INTENSITY] = args[LIGHT_INTENSITY] * 2 / 3; + args[LIGHT_SECONDARY_INTENSITY] = args[LIGHT_SECONDARY_INTENSITY] * 2 / 3; } } @@ -241,7 +195,7 @@ void ADynamicLight::Activate(AActor *activator) //Super::Activate(activator); flags2&=~MF2_DORMANT; - m_currentRadius = float(m_Radius[0]); + m_currentRadius = float(args[LIGHT_INTENSITY]); m_tickCount = 0; if (lighttype == PulseLight) @@ -249,7 +203,7 @@ void ADynamicLight::Activate(AActor *activator) float pulseTime = specialf1 / TICRATE; 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.SetCycleType(CYCLE_Sin); m_currentRadius = m_cycler.GetVal(); @@ -309,22 +263,22 @@ void ADynamicLight::Tick() BYTE rnd = randLight(); float pct = specialf1 / 360.f; - m_currentRadius = float(m_Radius[rnd >= pct * 255]); + m_currentRadius = float(args[LIGHT_INTENSITY + (rnd >= pct * 255)]); break; } case RandomFlickerLight: { - int flickerRange = m_Radius[1] - m_Radius[0]; + int flickerRange = args[LIGHT_SECONDARY_INTENSITY] - args[LIGHT_INTENSITY]; float amt = randLight() / 255.f; if (m_tickCount > specialf1) { 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; } @@ -342,14 +296,14 @@ void ADynamicLight::Tick() case RandomColorFlickerLight: { - int flickerRange = m_Radius[1] - m_Radius[0]; + int flickerRange = args[LIGHT_SECONDARY_INTENSITY] - args[LIGHT_INTENSITY]; float amt = randLight() / 255.f; m_tickCount++; if (m_tickCount > specialf1) { - m_currentRadius = m_Radius[0] + (amt * flickerRange); + m_currentRadius = args[LIGHT_INTENSITY] + (amt * flickerRange); m_tickCount = 0; } break; @@ -371,7 +325,7 @@ void ADynamicLight::Tick() } case PointLight: - m_currentRadius = float(m_Radius[0]); + m_currentRadius = float(args[LIGHT_INTENSITY]); break; } UpdateLocation(); @@ -423,7 +377,7 @@ void ADynamicLight::UpdateLocation() 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 { diff --git a/src/gl/dynlights/gl_dynlight.cpp b/src/gl/dynlights/gl_dynlight.cpp index a0d9292a9..ddc560b28 100644 --- a/src/gl/dynlights/gl_dynlight.cpp +++ b/src/gl/dynlights/gl_dynlight.cpp @@ -178,8 +178,8 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const light->SetOffset(m_Pos); light->halo = m_halo; for (int a = 0; a < 3; a++) light->args[a] = clamp((int)(m_Args[a]), 0, 255); - light->m_Radius[0] = int(m_Args[LIGHT_INTENSITY]); - light->m_Radius[1] = int(m_Args[LIGHT_SECONDARY_INTENSITY]); + light->args[LIGHT_INTENSITY] = int(m_Args[LIGHT_INTENSITY]); + light->args[LIGHT_SECONDARY_INTENSITY] = int(m_Args[LIGHT_SECONDARY_INTENSITY]); light->flags4 &= ~(MF4_ADDITIVE | MF4_SUBTRACTIVE | MF4_DONTLIGHTSELF); if (m_subtractive) light->flags4 |= MF4_SUBTRACTIVE; if (m_additive) light->flags4 |= MF4_ADDITIVE; @@ -190,7 +190,7 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const float pulseTime = float(m_Param / TICRATE); 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.SetCycleType(CYCLE_Sin); light->m_currentRadius = light->m_cycler.GetVal(); diff --git a/src/gl/dynlights/gl_dynlight.h b/src/gl/dynlights/gl_dynlight.h index 25d091150..ee581e74a 100644 --- a/src/gl/dynlights/gl_dynlight.h +++ b/src/gl/dynlights/gl_dynlight.h @@ -135,7 +135,6 @@ protected: public: int m_tickCount; - int m_Radius[2]; BYTE lightflags; BYTE lighttype; 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 { STAT_DLIGHT=64 diff --git a/src/info.cpp b/src/info.cpp index bdfcb4057..a424c890f 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -758,6 +758,14 @@ bool DamageTypeDefinition::IgnoreArmor(FName type) return false; } +DEFINE_ACTION_FUNCTION(_DamageTypeDefinition, IgnoreArmor) +{ + PARAM_PROLOGUE; + PARAM_NAME(type); + ACTION_RETURN_BOOL(DamageTypeDefinition::IgnoreArmor(type)); +} + + //========================================================================== // // DamageTypeDefinition :: ApplyMobjDamageFactor diff --git a/src/info.h b/src/info.h index 54aac3e3c..4a6baa671 100644 --- a/src/info.h +++ b/src/info.h @@ -226,10 +226,12 @@ public: NoArmor = false; } - static DamageTypeDefinition *Get(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); + +private: + static double GetMobjDamageFactor(FName type, DmgFactors const * const factors); + static DamageTypeDefinition *Get(FName type); }; class DDropItem; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index d68839359..2f99ea61c 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -47,8 +47,6 @@ #include "serializer.h" #include "r_utility.h" #include "a_morph.h" -#include "a_armor.h" -#include "a_ammo.h" #include "g_levellocals.h" #include "virtual.h" @@ -267,7 +265,7 @@ void cht_DoCheat (player_t *player, int cheat) } 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 (i != 0) @@ -319,7 +317,7 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_RESSURECT: 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"); } @@ -488,7 +486,7 @@ void cht_DoCheat (player_t *player, int cheat) int oldpieces = 1; ret.IntAt(&oldpieces); 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) { diff --git a/src/namedef.h b/src/namedef.h index 0a3af96cb..b730e93aa 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -83,6 +83,20 @@ xx(PointPuller) xx(UpperStackLookOnly) 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(StrifePuff) xx(MaulerPuff) @@ -716,6 +730,8 @@ xx(BlendColor) xx(Strength) xx(Mode) xx(PowerupType) +xx(PlayerPawn) +xx(Key) // Decorate compatibility functions xx(BuiltinTypeCheck) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 8914ab788..50f50ff31 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -83,8 +83,6 @@ #include "serializer.h" #include "thingdef.h" #include "a_pickups.h" -#include "a_armor.h" -#include "a_ammo.h" #include "r_data/colormaps.h" #include "g_levellocals.h" #include "stats.h" @@ -4956,8 +4954,8 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) else { FName p(FBehavior::StaticLookupString(args[0])); - ABasicArmor * armor = (ABasicArmor *) players[args[1]].mo->FindInventory(NAME_BasicArmor); - if (armor && armor->ArmorType == p) return armor->Amount; + auto armor = players[args[1]].mo->FindInventory(NAME_BasicArmor); + if (armor && armor->NameVar(NAME_ArmorType) == p) return armor->Amount; } return 0; } @@ -4966,29 +4964,29 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) { 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) { switch(args[0]) { case ARMORINFO_CLASSNAME: - return GlobalACSStrings.AddString(equippedarmor->ArmorType.GetChars()); + return GlobalACSStrings.AddString(equippedarmor->NameVar(NAME_ArmorType).GetChars()); case ARMORINFO_SAVEAMOUNT: - return equippedarmor->MaxAmount; + return equippedarmor->IntVar(NAME_MaxAmount); case ARMORINFO_SAVEPERCENT: - return DoubleToACS(equippedarmor->SavePercent); + return DoubleToACS(equippedarmor->FloatVar(NAME_SavePercent)); case ARMORINFO_MAXABSORB: - return equippedarmor->MaxAbsorb; + return equippedarmor->IntVar(NAME_MaxAbsorb); case ARMORINFO_MAXFULLABSORB: - return equippedarmor->MaxFullAbsorb; + return equippedarmor->IntVar(NAME_MaxFullAbsorb); case ARMORINFO_ACTUALSAVEAMOUNT: - return equippedarmor->ActualSaveAmount; + return equippedarmor->IntVar(NAME_ActualSaveAmount); default: return 0; @@ -8236,7 +8234,7 @@ scriptwait: case PCD_PLAYERARMORPOINTS: if (activator) { - ABasicArmor *armor = activator->FindInventory(); + auto armor = activator->FindInventory(NAME_BasicArmor); PushToStack (armor ? armor->Amount : 0); } else @@ -8683,7 +8681,7 @@ scriptwait: { AInventory *sigil; - if (activator == NULL || (sigil = activator->FindInventory(PClass::FindActor(NAME_Sigil))) == NULL) + if (activator == NULL || (sigil = activator->FindInventory(NAME_Sigil)) == NULL) { PushToStack (0); } @@ -8700,7 +8698,7 @@ scriptwait: PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(1))); AInventory *item; - if (type != NULL && type->ParentClass == RUNTIME_CLASS(AAmmo)) + if (type != NULL && type->ParentClass == PClass::FindActor(NAME_Ammo)) { item = activator->FindInventory (static_cast(type)); if (item != NULL) @@ -8729,7 +8727,7 @@ scriptwait: PClassActor *type = PClass::FindActor (FBehavior::StaticLookupString (STACK(2))); AInventory *item; - if (type != NULL && type->ParentClass == RUNTIME_CLASS(AAmmo)) + if (type != NULL && type->ParentClass == PClass::FindActor(NAME_Ammo)) { item = activator->FindInventory (type); if (item != NULL) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 172e17198..3c4978e0d 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -78,7 +78,6 @@ #include "v_text.h" #include "thingdef.h" #include "math/cmath.h" -#include "a_armor.h" #include "g_levellocals.h" AActor *SingleActorFromTID(int tid, AActor *defactor); @@ -2059,7 +2058,7 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_CustomPunch) PARAM_FLOAT_DEF (range); PARAM_FLOAT_DEF (lifesteal); PARAM_INT_DEF (lifestealmax); - PARAM_CLASS_DEF (armorbonustype, ABasicArmorBonus); + PARAM_CLASS_DEF (armorbonustype, AActor); PARAM_SOUND_DEF (MeleeSound); PARAM_SOUND_DEF (MissSound); @@ -2107,18 +2106,17 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_CustomPunch) { if (armorbonustype == NULL) { - armorbonustype = dyn_cast(PClass::FindClass("ArmorBonus")); + armorbonustype = PClass::FindActor("ArmorBonus"); } if (armorbonustype != NULL) { - assert(armorbonustype->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))); - ABasicArmorBonus *armorbonus = static_cast(Spawn(armorbonustype)); - armorbonus->SaveAmount *= int(actualdamage * lifesteal); - armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax; + auto armorbonus = Spawn(armorbonustype); + armorbonus->IntVar(NAME_SaveAmount) *= int(actualdamage * lifesteal); + if (lifestealmax > 0) armorbonus->IntVar("MaxSaveAmount") = lifestealmax; armorbonus->flags |= MF_DROPPED; armorbonus->ClearCounters(); - if (!armorbonus->CallTryPickup(self)) + if (!static_cast(armorbonus)->CallTryPickup(self)) { armorbonus->Destroy (); } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 0de02656d..ac6c2bc23 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -642,7 +642,7 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount) return; // Don't take keys. - if (itemtype->IsDescendantOf (RUNTIME_CLASS(AKey))) + if (itemtype->IsDescendantOf (PClass::FindActor(NAME_Key))) return; // Don't take the sigil. diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 83b96af39..e4a902b44 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -51,7 +51,6 @@ #include "p_spec.h" #include "p_checkposition.h" #include "math/cmath.h" -#include "a_ammo.h" #include "g_levellocals.h" #include "gi.h" @@ -3228,7 +3227,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount) 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->ItemFlags |= IF_IGNORESKILL; @@ -3238,10 +3237,10 @@ void ModifyDropAmount(AInventory *inv, int 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. - int amount = static_cast(inv)->DropAmount; + int amount = inv->IntVar("DropAmount"); if (amount <= 0) { amount = MAX(1, int(inv->Amount * dropammofactor)); diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index bfe341265..43ed096e0 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -1456,13 +1456,12 @@ void P_SetRenderSector() 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]) - { - segs[i].PartnerSeg = nullptr; - } + segs[i].PartnerSeg = nullptr; } } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index a09ad16cf..900f79497 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2883,7 +2883,7 @@ FUNC(LS_SetPlayerProperty) { // Take power from activator if (power != 4) { - AInventory *item = it->FindInventory(PClass::FindActor(powers[power]), true); + AInventory *item = it->FindInventory(powers[power], true); if (item != NULL) { item->Destroy (); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 4bf890462..1ca9baac8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -69,8 +69,6 @@ #include "thingdef.h" #include "d_player.h" #include "virtual.h" -#include "a_armor.h" -#include "a_ammo.h" #include "g_levellocals.h" #include "a_morph.h" @@ -791,13 +789,9 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) item->ClearCounters(); 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(item)->SaveAmount *= amount; - } - else if (type->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))) - { - static_cast(item)->SaveAmount *= amount; + item->IntVar(NAME_SaveAmount) *= amount; } else { @@ -899,14 +893,11 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate 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 // and infinite ammo is on if (notakeinfinite && ((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? result = false; @@ -1098,9 +1089,9 @@ AInventory *AActor::FindInventory (PClassActor *type, bool subclass) 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) @@ -1171,7 +1162,7 @@ bool AActor::GiveAmmo (PClassInventory *type, int amount) DEFINE_ACTION_FUNCTION(AActor, GiveAmmo) { PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS(type, AAmmo); + PARAM_CLASS(type, AInventory); PARAM_INT(amount); ACTION_RETURN_BOOL(self->GiveAmmo(type, amount)); } @@ -1212,12 +1203,7 @@ void AActor::ClearInventory() if (!(inv->ItemFlags & IF_UNDROPPABLE)) { inv->DepleteOrDestroy(); - } - else if (inv->GetClass() == RUNTIME_CLASS(AHexenArmor)) - { - AHexenArmor *harmor = static_cast (inv); - harmor->Slots[3] = harmor->Slots[2] = harmor->Slots[1] = harmor->Slots[0] = 0; - invp = &inv->Inventory; + if (!(inv->ObjectFlags & OF_EuthanizeMe)) invp = &inv->Inventory; // was only depleted so advance the pointer manually. } else { @@ -5711,7 +5697,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) } if (dmflags & DF_NO_ARMOR) { - if (i->IsDescendantOf (RUNTIME_CLASS(AArmor))) + if (i->IsDescendantOf (PClass::FindActor(NAME_Armor))) return NULL; if (i->TypeName == NAME_Megasphere) return NULL; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index e46b63436..4128dca12 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -237,7 +237,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) { if (mo != nullptr) { - newcaller = mo->FindInventory(PClass::FindActor(NAME_PowerTargeter), true); + newcaller = mo->FindInventory(NAME_PowerTargeter, true); } } else if (layer == PSP_STRIFEHANDS) diff --git a/src/p_user.cpp b/src/p_user.cpp index 5397fa733..aabf9f959 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -59,8 +59,6 @@ #include "a_morph.h" #include "p_spec.h" #include "virtual.h" -#include "a_armor.h" -#include "a_ammo.h" #include "g_levellocals.h" static FRandom pr_skullpop ("SkullPop"); @@ -660,8 +658,6 @@ IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTER(FlechetteType) IMPLEMENT_POINTERS_END -IMPLEMENT_CLASS(APlayerChunk, false, false) - void APlayerPawn::Serialize(FSerializer &arc) { Super::Serialize (arc); @@ -1076,12 +1072,12 @@ void APlayerPawn::GiveDeathmatchInventory() { 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]); - if (key->KeyNumber != 0) + AInventory *key = (AInventory*)GetDefaultByType (PClassActor::AllActorClasses[i]); + if (key->special1 != 0) { - key = static_cast(Spawn(static_cast(PClassActor::AllActorClasses[i]))); + key = (AInventory*)Spawn(PClassActor::AllActorClasses[i]); if (!key->CallTryPickup (this)) { key->Destroy (); @@ -1134,7 +1130,7 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer) if ((dmflags & DF_COOP_LOSE_KEYS) && defitem == NULL && - item->IsKindOf(RUNTIME_CLASS(AKey))) + item->IsKindOf(PClass::FindActor(NAME_Key))) { item->Destroy(); } @@ -1145,23 +1141,22 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer) item->Destroy(); } else if ((dmflags & DF_COOP_LOSE_ARMOR) && - item->IsKindOf(RUNTIME_CLASS(AArmor))) + item->IsKindOf(PClass::FindActor(NAME_Armor))) { if (defitem == NULL) { item->Destroy(); } - else if (item->IsKindOf(RUNTIME_CLASS(ABasicArmor))) + else if (item->IsKindOf(PClass::FindActor(NAME_BasicArmor))) { - static_cast(item)->SavePercent = static_cast(defitem)->SavePercent; + item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent); item->Amount = defitem->Amount; } - else if (item->IsKindOf(RUNTIME_CLASS(AHexenArmor))) + else if (item->IsKindOf(PClass::FindActor(NAME_HexenArmor))) { - static_cast(item)->Slots[0] = static_cast(defitem)->Slots[0]; - static_cast(item)->Slots[1] = static_cast(defitem)->Slots[1]; - static_cast(item)->Slots[2] = static_cast(defitem)->Slots[2]; - static_cast(item)->Slots[3] = static_cast(defitem)->Slots[3]; + double *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr); + double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr); + memcpy(SlotsTo, SlotsFrom, 4 * sizeof(double)); } } else if ((dmflags & DF_COOP_LOSE_POWERUPS) && @@ -1171,7 +1166,7 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer) item->Destroy(); } 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) { @@ -1367,21 +1362,22 @@ void APlayerPawn::GiveDefaultInventory () // it provides player class based protection that should not affect // any other protection item. PClassPlayerPawn *myclass = GetClass(); - GiveInventoryType(RUNTIME_CLASS(AHexenArmor)); - AHexenArmor *harmor = FindInventory(); - harmor->Slots[4] = myclass->HexenArmor[0]; + GiveInventoryType(PClass::FindActor(NAME_HexenArmor)); + auto harmor = FindInventory(NAME_HexenArmor); + + 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) { - harmor->SlotsIncrement[i] = myclass->HexenArmor[i + 1]; + SlotsIncrement[i] = myclass->HexenArmor[i + 1]; } // BasicArmor must come right after that. It should not affect any // other protection item as well but needs to process the damage // before the HexenArmor does. - ABasicArmor *barmor = Spawn (); + auto barmor = (AInventory*)Spawn(NAME_BasicArmor); barmor->BecomeItem (); - barmor->SavePercent = 0; - barmor->Amount = 0; AddInventory (barmor); // Now add the items from the DECORATE definition @@ -1701,13 +1697,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) DEFINE_ACTION_FUNCTION(AActor, A_SkullPop) { PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS_DEF(spawntype, APlayerChunk); + PARAM_CLASS_DEF(spawntype, APlayerPawn); APlayerPawn *mo; player_t *player; // [GRB] Parameterized version - if (spawntype == NULL || !spawntype->IsDescendantOf(RUNTIME_CLASS(APlayerChunk))) + if (spawntype == NULL || !spawntype->IsDescendantOf(PClass::FindActor("PlayerChunk"))) { spawntype = dyn_cast(PClass::FindClass("BloodySkull")); if (spawntype == NULL) @@ -2205,7 +2201,7 @@ void P_DeathThink (player_t *player) player->TickPSprites(); 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 player->viewheight = 6; player->deltaviewheight = 0; diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index c94e320be..c126e3d57 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -56,7 +56,7 @@ #include "m_argv.h" #include "p_local.h" #include "doomerrors.h" -#include "a_weaponpiece.h" +#include "a_weapons.h" #include "p_conversation.h" #include "v_text.h" #include "thingdef.h" diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 3eed959f3..6cb482ed8 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -46,7 +46,6 @@ #include "templates.h" #include "r_defs.h" #include "a_pickups.h" -#include "a_armor.h" #include "s_sound.h" #include "cmdlib.h" #include "p_lnspec.h" @@ -67,9 +66,7 @@ #include "teaminfo.h" #include "v_video.h" #include "r_data/colormaps.h" -#include "a_weaponpiece.h" #include "vmbuilder.h" -#include "a_ammo.h" #include "a_keys.h" #include "g_levellocals.h" @@ -98,9 +95,9 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool } return static_cast(cls); } -static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false) +static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(AAmmo), optional)); + return static_cast(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional)); } 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); } -static void *ScriptVar(DObject *obj, PClass *cls, FName field, PType *type) -{ - auto sym = dyn_cast(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 -T &TypedScriptVar(DObject *obj, PClass *cls, FName field, PType *type) -{ - return *(T*)ScriptVar(obj, cls, field, type); -} - //========================================================================== // // 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 } -//========================================================================== -// -//========================================================================== -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); } } - TypedScriptVar(defaults, info, NAME_PowerupType, NewClassPointer(RUNTIME_CLASS(AActor))) = cls; + defaults->PointerVar(NAME_PowerupType) = cls; } //========================================================================== @@ -3018,7 +2837,7 @@ DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile) DEFINE_SCRIPTED_PROPERTY(playerclass, S, PowerMorph) { PROP_STRING_PARM(str, 0); - TypedScriptVar(defaults, bag.Info, NAME_PlayerClass, NewClassPointer(RUNTIME_CLASS(APlayerPawn))) = FindClassTentativePlayerPawn(str, bag.fromDecorate); + defaults->PointerVar(NAME_PlayerClass) = FindClassTentativePlayerPawn(str, bag.fromDecorate); } //========================================================================== @@ -3027,7 +2846,7 @@ DEFINE_SCRIPTED_PROPERTY(playerclass, S, PowerMorph) DEFINE_SCRIPTED_PROPERTY(morphstyle, M, PowerMorph) { PROP_INT_PARM(i, 0); - TypedScriptVar(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) { PROP_STRING_PARM(str, 0); - TypedScriptVar(defaults, bag.Info, NAME_MorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + defaults->PointerVar(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) { PROP_STRING_PARM(str, 0); - TypedScriptVar(defaults, bag.Info, NAME_UnMorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + defaults->PointerVar(NAME_UnMorphFlash) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index da10c0cfb..f03122edf 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1380,16 +1380,24 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray &Proper TArray fields; ZCC_Identifier *id = (ZCC_Identifier *)p->Body; - do + if (FName(p->NodeName) == FName("prefix") && Wads.GetLumpFile(Lump) == 0) { - auto f = dyn_cast(type->Symbols.FindSymbol(id->Id, true)); - if (f == nullptr) + // 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 { - Error(id, "Variable %s not found in %s", FName(id->Id).GetChars(), type->TypeName.GetChars()); - } - fields.Push(f); - id = (ZCC_Identifier*)id->SiblingNext; - } while (id != p->Body); + auto f = dyn_cast(type->Symbols.FindSymbol(id->Id, true)); + if (f == nullptr) + { + Error(id, "Variable %s not found in %s", FName(id->Id).GetChars(), type->TypeName.GetChars()); + } + fields.Push(f); + id = (ZCC_Identifier*)id->SiblingNext; + } while (id != p->Body); + } FString qualifiedname; // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index fd8bce922..6f0e3a516 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -9,6 +9,7 @@ #include "zscript/inventory/inventory.txt" #include "zscript/inventory/inv_misc.txt" #include "zscript/inventory/weapons.txt" +#include "zscript/inventory/weaponpiece.txt" #include "zscript/inventory/armor.txt" #include "zscript/inventory/ammo.txt" #include "zscript/inventory/health.txt" diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 9cad3224e..2cf48363b 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -42,11 +42,18 @@ struct Console native native static void HideConsole(); } +struct DamageTypeDefinition native +{ + native static bool IgnoreArmor(Name type); +} + struct GameInfoStruct native { // will be extended as needed. native Name backpacktype; native double Armor2Percent; + native String ArmorIcon1; + native String ArmorIcon2; } class Object native diff --git a/wadsrc/static/zscript/inventory/ammo.txt b/wadsrc/static/zscript/inventory/ammo.txt index be9933a70..ba087a894 100644 --- a/wadsrc/static/zscript/inventory/ammo.txt +++ b/wadsrc/static/zscript/inventory/ammo.txt @@ -4,7 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2000-2016 Randy Heit -** Copyright 2006-2017 Cheistoph Oelckers +** Copyright 2006-2017 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -33,18 +33,49 @@ ** */ -class Ammo : Inventory native +class Ammo : Inventory { - native int BackpackAmount; - native int BackpackMaxAmount; + int BackpackAmount; + int BackpackMaxAmount; + /*meta*/ int DropAmount; + property BackpackAmount: BackpackAmount; + property BackpackMaxAmount: BackpackMaxAmount; + property DropAmount: DropAmount; + Default { +INVENTORY.KEEPDEPLETED Inventory.PickupSound "misc/ammo_pkup"; } - native Class 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 GetParentAmmo () + { + class type = GetClass(); + + while (type.GetParentClass() != "Ammo" && type.GetParentClass() != NULL) + { + type = type.GetParentClass(); + } + return (class)(type); + } //=========================================================================== // @@ -113,7 +144,7 @@ class Ammo : Inventory native } let type = GetParentAmmo(); - if (GetClass() == type) + if (GetClass() != type && type != null) { if (!GoAway ()) { diff --git a/wadsrc/static/zscript/inventory/armor.txt b/wadsrc/static/zscript/inventory/armor.txt index 3e7f57e21..50161e8af 100644 --- a/wadsrc/static/zscript/inventory/armor.txt +++ b/wadsrc/static/zscript/inventory/armor.txt @@ -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 { @@ -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; - native double SavePercent; - native int MaxAbsorb; - native int MaxFullAbsorb; - native int BonusCount; - native Name ArmorType; - native int ActualSaveAmount; + int AbsorbCount; + double SavePercent; + int MaxAbsorb; + int MaxFullAbsorb; + int BonusCount; + Name ArmorType; + int ActualSaveAmount; Default { + Inventory.Amount 0; +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); + } + } + + //=========================================================================== + // + // ABasicArmor :: CreateCopy + // + //=========================================================================== + + override Inventory CreateCopy (Actor other) + { + // BasicArmor that is in use is stored in the inventory as BasicArmor. + // BasicArmor that is in reserve is not. + let copy = BasicArmor(Spawn("BasicArmor")); + 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 + // + //=========================================================================== + + 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); + } + } } -class BasicArmorBonus : Armor native +//=========================================================================== +// +// +// BasicArmorBonus +// +// +//=========================================================================== + +class BasicArmorBonus : Armor { - native double SavePercent; // The default, for when you don't already have armor - native int MaxSaveAmount; - native int MaxAbsorb; - native int MaxFullAbsorb; - native int SaveAmount; - native int BonusCount; - native int BonusMax; + 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 { @@ -40,33 +252,365 @@ class BasicArmorBonus : Armor native Inventory.MaxAmount 0; 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)); + } + + 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; + } + + } -class BasicArmorPickup : Armor native +//=========================================================================== +// +// +// BasicArmorPickup +// +// +//=========================================================================== + +class BasicArmorPickup : Armor { - native double SavePercent; - native int MaxAbsorb; - native int MaxFullAbsorb; - native int SaveAmount; - + double SavePercent; + int MaxAbsorb; + int MaxFullAbsorb; + int SaveAmount; + + property prefix: Armor; + property SaveAmount : SaveAmount; + property SavePercent: SavePercent; + property MaxAbsorb: MaxAbsorb; + property MaxFullAbsorb: MaxFullAbsorb; + Default { +Inventory.AUTOACTIVATE; 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)); + } + + 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; + } } -class HexenArmor : Armor native +//=========================================================================== +// +// +// 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]; - native double SlotsIncrement[4]; + double Slots[5]; + double SlotsIncrement[4]; Default { +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; + } + } } diff --git a/wadsrc/static/zscript/inventory/inv_misc.txt b/wadsrc/static/zscript/inventory/inv_misc.txt index 9bea4c7bf..9f13ab957 100644 --- a/wadsrc/static/zscript/inventory/inv_misc.txt +++ b/wadsrc/static/zscript/inventory/inv_misc.txt @@ -28,10 +28,8 @@ class ScoreItem : Inventory // //=========================================================================== -class Key : Inventory native +class Key : Inventory { - native uint8 KeyNumber; - Default { +DONTGIB; // Don't disappear due to a crusher diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index 3e01d059e..2b0d6d0c7 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -47,44 +47,12 @@ class Inventory : Actor native virtual native bool DrawPowerup(int x, int y); virtual native void AbsorbDamage (int damage, Name damageType, out int newdamage); - //=========================================================================== - // - // 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 DoRespawn(); native bool GoAway(); native void GoAwayAndDie(); native void BecomeItem(); 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 // is what must be actually called to pick up an item. virtual protected native bool TryPickup(in out Actor toucher); @@ -112,6 +80,118 @@ class Inventory : Actor native TNT1 A 1; 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 diff --git a/wadsrc/static/zscript/inventory/weaponpiece.txt b/wadsrc/static/zscript/inventory/weaponpiece.txt new file mode 100644 index 000000000..af816aabc --- /dev/null +++ b/wadsrc/static/zscript/inventory/weaponpiece.txt @@ -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 PieceWeapon; + + Default + { + +NOBLOCKMAP + +NOSECTOR + +INVENTORY.UNDROPPABLE + } +} + +class WeaponPiece : Inventory +{ + Default + { + +WEAPONSPAWN; + } + + int PieceValue; + Class 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); + } + } +} diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index ba2bf2ef5..303dc6aa9 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -104,27 +104,6 @@ class WeaponGiver : Weapon native } } -class WeaponHolder : Inventory native -{ - native int PieceMask; - native Class PieceWeapon; - - Default - { - +NOBLOCKMAP - +NOSECTOR - +INVENTORY.UNDROPPABLE - } -} - -class WeaponPiece : Inventory native -{ - Default - { - +WEAPONSPAWN; - } -} - struct WeaponSlots native { native bool, int, int LocateWeapon(class weap); diff --git a/wadsrc/static/zscript/shared/dynlights.txt b/wadsrc/static/zscript/shared/dynlights.txt index f851d88d0..a39b682fe 100644 --- a/wadsrc/static/zscript/shared/dynlights.txt +++ b/wadsrc/static/zscript/shared/dynlights.txt @@ -1,5 +1,28 @@ 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 { 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 { 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(); + } +} + + diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index dd6084e1d..830247c08 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -138,7 +138,7 @@ class PlayerPawn : Actor native native void CheckWeaponSwitch(class item); } -class PlayerChunk : PlayerPawn native +class PlayerChunk : PlayerPawn { Default { diff --git a/wadsrc/static/zscript/shared/player_cheat.txt b/wadsrc/static/zscript/shared/player_cheat.txt index 30760fb5d..b88c387a1 100644 --- a/wadsrc/static/zscript/shared/player_cheat.txt +++ b/wadsrc/static/zscript/shared/player_cheat.txt @@ -157,8 +157,8 @@ extend class PlayerPawn { if (AllActorClasses[i] is "Key") { - readonly keyitem = GetDefaultByType ((class)(AllActorClasses[i])); - if (keyitem.KeyNumber != 0) + let keyitem = GetDefaultByType (AllActorClasses[i]); + if (keyitem.special1 != 0) { let item = Inventory(Spawn(AllActorClasses[i])); if (!item.CallTryPickup (self)) @@ -399,4 +399,4 @@ extend class PlayerPawn } return; } -} \ No newline at end of file +}