mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-23 20:43:15 +00:00
Merge branch 'master' of https://github.com/raa-eruanna/qzdoom into qzdoom
This commit is contained in:
commit
e235d83e5b
63 changed files with 1354 additions and 1931 deletions
|
@ -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
|
||||
|
|
|
@ -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<class T> T *FindInventory ()
|
||||
{
|
||||
return static_cast<T *> (FindInventory (RUNTIME_TEMPLATE_CLASS(T)));
|
||||
|
|
|
@ -2740,8 +2740,8 @@ void AM_drawKeys ()
|
|||
mpoint_t p;
|
||||
DAngle angle;
|
||||
|
||||
TThinkerIterator<AKey> it;
|
||||
AKey *key;
|
||||
TThinkerIterator<AInventory> 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<AKey *>(t));
|
||||
int c = P_GetMapColorForKey(static_cast<AInventory *>(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)
|
||||
{
|
||||
|
|
|
@ -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<AAmmo *> (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;
|
||||
|
|
|
@ -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<ABasicArmor>();
|
||||
AInventory *armor = player->mo->FindInventory(NAME_BasicArmor);
|
||||
out.AppendFormat("%d", armor != NULL ? armor->Amount : 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ABasicArmorPickup *> (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<ABasicArmorPickup *> (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<ABasicArmorBonus *> (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)
|
||||
|
|
|
@ -177,11 +177,6 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class APlayerChunk : public APlayerPawn
|
||||
{
|
||||
DECLARE_CLASS (APlayerChunk, APlayerPawn)
|
||||
};
|
||||
|
||||
//
|
||||
// PlayerPawn flags
|
||||
//
|
||||
|
|
|
@ -571,7 +571,7 @@ DEFINE_ACTION_FUNCTION(DObject, GetClassName)
|
|||
void *DObject::ScriptVar(FName field, PType *type)
|
||||
{
|
||||
auto sym = dyn_cast<PField>(GetClass()->Symbols.FindSymbol(field, true));
|
||||
if (sym && sym->Type == type)
|
||||
if (sym && (sym->Type == type || type == nullptr))
|
||||
{
|
||||
return (((char*)this) + sym->Offset);
|
||||
}
|
||||
|
|
|
@ -482,6 +482,7 @@ public:
|
|||
PalEntry &ColorVar(FName field);
|
||||
FName &NameVar(FName field);
|
||||
double &FloatVar(FName field);
|
||||
template<class T> T*& PointerVar(FName field);
|
||||
|
||||
// If you need to replace one object with another and want to
|
||||
// change any pointers from the old object to the new object,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1093,5 +1093,9 @@ inline double &DObject::FloatVar(FName field)
|
|||
return *(double*)ScriptVar(field, TypeFloat64);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline T *&DObject::PointerVar(FName field)
|
||||
{
|
||||
return *(T**)ScriptVar(field, nullptr); // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle.
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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<AAmmo *>(Spawn (ammotype));
|
||||
iammo = static_cast<AInventory *>(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
** a_ammo.cpp
|
||||
** Implements ammo and backpack items.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2000-2016 Randy Heit
|
||||
** Copyright 2006-2016 Cheistoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "c_dispatch.h"
|
||||
#include "d_player.h"
|
||||
#include "serializer.h"
|
||||
|
||||
IMPLEMENT_CLASS(AAmmo, false, false)
|
||||
|
||||
DEFINE_FIELD(AAmmo, BackpackAmount)
|
||||
DEFINE_FIELD(AAmmo, BackpackMaxAmount)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AAmmo :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AAmmo::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (AAmmo*)GetDefault();
|
||||
arc("backpackamount", BackpackAmount, def->BackpackAmount)
|
||||
("backpackmaxamount", BackpackMaxAmount, def->BackpackMaxAmount);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AAmmo :: GetParentAmmo
|
||||
//
|
||||
// Returns the least-derived ammo type that this ammo is a descendant of.
|
||||
// That is, if this ammo is an immediate subclass of Ammo, then this ammo's
|
||||
// type is returned. If this ammo's superclass is not Ammo, then this
|
||||
// function travels up the inheritance chain until it finds a type that is
|
||||
// an immediate subclass of Ammo and returns that.
|
||||
//
|
||||
// The intent of this is that all unique ammo types will be immediate
|
||||
// subclasses of Ammo. To make different pickups with different ammo amounts,
|
||||
// you subclass the type of ammo you want a different amount for and edit
|
||||
// that.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
PClassActor *AAmmo::GetParentAmmo () const
|
||||
{
|
||||
PClass *type = GetClass();
|
||||
|
||||
while (type->ParentClass != RUNTIME_CLASS(AAmmo) && type->ParentClass != NULL)
|
||||
{
|
||||
type = type->ParentClass;
|
||||
}
|
||||
return static_cast<PClassActor *>(type);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AAmmo, GetParentAmmo)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AAmmo);
|
||||
ACTION_RETURN_OBJECT(self->GetParentAmmo());
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -1,644 +0,0 @@
|
|||
/*
|
||||
** a_armor.cpp
|
||||
** Implements all variations of armor objects
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2016 Randy Heit
|
||||
** Copyright 2006-2016 Cheistoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "info.h"
|
||||
#include "gi.h"
|
||||
#include "a_pickups.h"
|
||||
#include "a_armor.h"
|
||||
#include "templates.h"
|
||||
#include "g_level.h"
|
||||
#include "d_player.h"
|
||||
#include "serializer.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
IMPLEMENT_CLASS(AArmor, false, false)
|
||||
IMPLEMENT_CLASS(ABasicArmor, false, false)
|
||||
IMPLEMENT_CLASS(ABasicArmorPickup, false, false)
|
||||
IMPLEMENT_CLASS(ABasicArmorBonus, false, false)
|
||||
IMPLEMENT_CLASS(AHexenArmor, false, false)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
// BasicArmor
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_FIELD(ABasicArmor, AbsorbCount)
|
||||
DEFINE_FIELD(ABasicArmor, SavePercent)
|
||||
DEFINE_FIELD(ABasicArmor, MaxAbsorb)
|
||||
DEFINE_FIELD(ABasicArmor, MaxFullAbsorb)
|
||||
DEFINE_FIELD(ABasicArmor, BonusCount)
|
||||
DEFINE_FIELD(ABasicArmor, ArmorType)
|
||||
DEFINE_FIELD(ABasicArmor, ActualSaveAmount)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmor::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (ABasicArmor *)GetDefault();
|
||||
arc("savepercent", SavePercent, def->SavePercent)
|
||||
("bonuscount", BonusCount, def->BonusCount)
|
||||
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
|
||||
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb)
|
||||
("absorbcount", AbsorbCount, def->AbsorbCount)
|
||||
("armortype", ArmorType, def->ArmorType)
|
||||
("actualsaveamount", ActualSaveAmount, def->ActualSaveAmount);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: Tick
|
||||
//
|
||||
// If BasicArmor is given to the player by means other than a
|
||||
// BasicArmorPickup, then it may not have an icon set. Fix that here.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmor::Tick ()
|
||||
{
|
||||
Super::Tick ();
|
||||
AbsorbCount = 0;
|
||||
if (!Icon.isValid())
|
||||
{
|
||||
FString icon = gameinfo.ArmorIcon1;
|
||||
|
||||
if (SavePercent >= gameinfo.Armor2Percent && gameinfo.ArmorIcon2.Len() != 0)
|
||||
icon = gameinfo.ArmorIcon2;
|
||||
|
||||
if (icon[0] != 0)
|
||||
Icon = TexMan.CheckForTexture (icon, FTexture::TEX_Any);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *ABasicArmor::CreateCopy (AActor *other)
|
||||
{
|
||||
// BasicArmor that is in use is stored in the inventory as BasicArmor.
|
||||
// BasicArmor that is in reserve is not.
|
||||
ABasicArmor *copy = Spawn<ABasicArmor> ();
|
||||
copy->SavePercent = SavePercent != 0 ? SavePercent : 0.33335; // slightly more than 1/3 to avoid roundoff errors.
|
||||
copy->Amount = Amount;
|
||||
copy->MaxAmount = MaxAmount;
|
||||
copy->Icon = Icon;
|
||||
copy->BonusCount = BonusCount;
|
||||
copy->ArmorType = ArmorType;
|
||||
copy->ActualSaveAmount = ActualSaveAmount;
|
||||
GoAwayAndDie ();
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: HandlePickup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool ABasicArmor::HandlePickup (AInventory *item)
|
||||
{
|
||||
if (item->GetClass() == RUNTIME_CLASS(ABasicArmor))
|
||||
{
|
||||
// You shouldn't be picking up BasicArmor anyway.
|
||||
return true;
|
||||
}
|
||||
if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorBonus)) && !(item->ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
ABasicArmorBonus *armor = static_cast<ABasicArmorBonus*>(item);
|
||||
|
||||
armor->SaveAmount = int(armor->SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
else if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorPickup)) && !(item->ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
ABasicArmorPickup *armor = static_cast<ABasicArmorPickup*>(item);
|
||||
|
||||
armor->SaveAmount = int(armor->SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: AbsorbDamage
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
|
||||
{
|
||||
int saved;
|
||||
|
||||
if (!DamageTypeDefinition::IgnoreArmor(damageType))
|
||||
{
|
||||
int full = MAX(0, MaxFullAbsorb - AbsorbCount);
|
||||
if (damage < full)
|
||||
{
|
||||
saved = damage;
|
||||
}
|
||||
else
|
||||
{
|
||||
saved = full + int((damage - full) * SavePercent);
|
||||
if (MaxAbsorb > 0 && saved + AbsorbCount > MaxAbsorb)
|
||||
{
|
||||
saved = MAX(0, MaxAbsorb - AbsorbCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (Amount < saved)
|
||||
{
|
||||
saved = Amount;
|
||||
}
|
||||
newdamage -= saved;
|
||||
Amount -= saved;
|
||||
AbsorbCount += saved;
|
||||
if (Amount == 0)
|
||||
{
|
||||
// The armor has become useless
|
||||
SavePercent = 0;
|
||||
ArmorType = NAME_None; // Not NAME_BasicArmor.
|
||||
// Now see if the player has some more armor in their inventory
|
||||
// and use it if so. As in Strife, the best armor is used up first.
|
||||
ABasicArmorPickup *best = NULL;
|
||||
AInventory *probe = Owner->Inventory;
|
||||
while (probe != NULL)
|
||||
{
|
||||
if (probe->IsKindOf (RUNTIME_CLASS(ABasicArmorPickup)))
|
||||
{
|
||||
ABasicArmorPickup *inInv = static_cast<ABasicArmorPickup*>(probe);
|
||||
if (best == NULL || best->SavePercent < inInv->SavePercent)
|
||||
{
|
||||
best = inInv;
|
||||
}
|
||||
}
|
||||
probe = probe->Inventory;
|
||||
}
|
||||
if (best != NULL)
|
||||
{
|
||||
Owner->UseInventory (best);
|
||||
}
|
||||
}
|
||||
damage = newdamage;
|
||||
}
|
||||
|
||||
// Once the armor has absorbed its part of the damage, then apply its damage factor, if any, to the player
|
||||
if ((damage > 0) && (ArmorType != NAME_None)) // BasicArmor is not going to have any damage factor, so skip it.
|
||||
{
|
||||
// This code is taken and adapted from APowerProtection::ModifyDamage().
|
||||
// The differences include not using a default value, and of course the way
|
||||
// the damage factor info is obtained.
|
||||
|
||||
// ApplyDamageFactors(ArmorType, damageType, damage, damage);
|
||||
DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors;
|
||||
if (df != NULL)
|
||||
{
|
||||
damage = newdamage = df->Apply(damageType, damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
// BasicArmorPickup
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
|
||||
DEFINE_FIELD(ABasicArmorPickup, SavePercent)
|
||||
DEFINE_FIELD(ABasicArmorPickup, MaxAbsorb)
|
||||
DEFINE_FIELD(ABasicArmorPickup, MaxFullAbsorb)
|
||||
DEFINE_FIELD(ABasicArmorPickup, SaveAmount)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorPickup :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmorPickup::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
|
||||
auto def = (ABasicArmorPickup *)GetDefault();
|
||||
arc("savepercent", SavePercent, def->SavePercent)
|
||||
("saveamount", SaveAmount, def->SaveAmount)
|
||||
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
|
||||
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorPickup :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *ABasicArmorPickup::CreateCopy (AActor *other)
|
||||
{
|
||||
ABasicArmorPickup *copy = static_cast<ABasicArmorPickup *> (Super::CreateCopy (other));
|
||||
|
||||
if (!(ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
SaveAmount = int(SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
|
||||
copy->SavePercent = SavePercent;
|
||||
copy->SaveAmount = SaveAmount;
|
||||
copy->MaxAbsorb = MaxAbsorb;
|
||||
copy->MaxFullAbsorb = MaxFullAbsorb;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorPickup :: Use
|
||||
//
|
||||
// Either gives you new armor or replaces the armor you already have (if
|
||||
// the SaveAmount is greater than the amount of armor you own). When the
|
||||
// item is auto-activated, it will only be activated if its max amount is 0
|
||||
// or if you have no armor active already.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool ABasicArmorPickup::Use (bool pickup)
|
||||
{
|
||||
ABasicArmor *armor = Owner->FindInventory<ABasicArmor> ();
|
||||
|
||||
if (armor == NULL)
|
||||
{
|
||||
armor = Spawn<ABasicArmor> ();
|
||||
armor->BecomeItem ();
|
||||
Owner->AddInventory (armor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If you already have more armor than this item gives you, you can't
|
||||
// use it.
|
||||
if (armor->Amount >= SaveAmount + armor->BonusCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Don't use it if you're picking it up and already have some.
|
||||
if (pickup && armor->Amount > 0 && MaxAmount > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
armor->SavePercent = SavePercent;
|
||||
armor->Amount = SaveAmount + armor->BonusCount;
|
||||
armor->MaxAmount = SaveAmount;
|
||||
armor->Icon = Icon;
|
||||
armor->MaxAbsorb = MaxAbsorb;
|
||||
armor->MaxFullAbsorb = MaxFullAbsorb;
|
||||
armor->ArmorType = this->GetClass()->TypeName;
|
||||
armor->ActualSaveAmount = SaveAmount;
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
// BasicArmorBonus
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
|
||||
DEFINE_FIELD(ABasicArmorBonus, SavePercent)
|
||||
DEFINE_FIELD(ABasicArmorBonus, MaxSaveAmount)
|
||||
DEFINE_FIELD(ABasicArmorBonus, MaxAbsorb)
|
||||
DEFINE_FIELD(ABasicArmorBonus, MaxFullAbsorb)
|
||||
DEFINE_FIELD(ABasicArmorBonus, SaveAmount)
|
||||
DEFINE_FIELD(ABasicArmorBonus, BonusCount)
|
||||
DEFINE_FIELD(ABasicArmorBonus, BonusMax)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorBonus :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmorBonus::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (ABasicArmorBonus *)GetDefault();
|
||||
arc("savepercent", SavePercent, def->SavePercent)
|
||||
("saveamount", SaveAmount, def->SaveAmount)
|
||||
("maxsaveamount", MaxSaveAmount, def->MaxSaveAmount)
|
||||
("bonuscount", BonusCount, def->BonusCount)
|
||||
("bonusmax", BonusMax, def->BonusMax)
|
||||
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
|
||||
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorBonus :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *ABasicArmorBonus::CreateCopy (AActor *other)
|
||||
{
|
||||
ABasicArmorBonus *copy = static_cast<ABasicArmorBonus *> (Super::CreateCopy (other));
|
||||
|
||||
if (!(ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
SaveAmount = int(SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
|
||||
copy->SavePercent = SavePercent;
|
||||
copy->SaveAmount = SaveAmount;
|
||||
copy->MaxSaveAmount = MaxSaveAmount;
|
||||
copy->BonusCount = BonusCount;
|
||||
copy->BonusMax = BonusMax;
|
||||
copy->MaxAbsorb = MaxAbsorb;
|
||||
copy->MaxFullAbsorb = MaxFullAbsorb;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorBonus :: Use
|
||||
//
|
||||
// Tries to add to the amount of BasicArmor a player has.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool ABasicArmorBonus::Use (bool pickup)
|
||||
{
|
||||
ABasicArmor *armor = Owner->FindInventory<ABasicArmor> ();
|
||||
bool result = false;
|
||||
|
||||
if (armor == NULL)
|
||||
{
|
||||
armor = Spawn<ABasicArmor> ();
|
||||
armor->BecomeItem ();
|
||||
armor->Amount = 0;
|
||||
armor->MaxAmount = MaxSaveAmount;
|
||||
Owner->AddInventory (armor);
|
||||
}
|
||||
|
||||
if (BonusCount > 0 && armor->BonusCount < BonusMax)
|
||||
{
|
||||
armor->BonusCount = MIN (armor->BonusCount + BonusCount, BonusMax);
|
||||
result = true;
|
||||
}
|
||||
|
||||
int saveAmount = MIN (SaveAmount, MaxSaveAmount);
|
||||
|
||||
if (saveAmount <= 0)
|
||||
{ // If it can't give you anything, it's as good as used.
|
||||
return BonusCount > 0 ? result : true;
|
||||
}
|
||||
|
||||
// If you already have more armor than this item can give you, you can't
|
||||
// use it.
|
||||
if (armor->Amount >= MaxSaveAmount + armor->BonusCount)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (armor->Amount <= 0)
|
||||
{ // Should never be less than 0, but might as well check anyway
|
||||
armor->Amount = 0;
|
||||
armor->Icon = Icon;
|
||||
armor->SavePercent = SavePercent;
|
||||
armor->MaxAbsorb = MaxAbsorb;
|
||||
armor->ArmorType = this->GetClass()->TypeName;
|
||||
armor->MaxFullAbsorb = MaxFullAbsorb;
|
||||
armor->ActualSaveAmount = MaxSaveAmount;
|
||||
}
|
||||
|
||||
armor->Amount = MIN(armor->Amount + saveAmount, MaxSaveAmount + armor->BonusCount);
|
||||
armor->MaxAmount = MAX (armor->MaxAmount, MaxSaveAmount);
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
// HexenArmor
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_FIELD(AHexenArmor, Slots)
|
||||
DEFINE_FIELD(AHexenArmor, SlotsIncrement)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AHexenArmor::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (AHexenArmor *)GetDefault();
|
||||
arc.Array("slots", Slots, def->Slots, 5, true)
|
||||
.Array("slotsincrement", SlotsIncrement, def->SlotsIncrement, 4);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AHexenArmor::CreateCopy (AActor *other)
|
||||
{
|
||||
// Like BasicArmor, HexenArmor is used in the inventory but not the map.
|
||||
// health is the slot this armor occupies.
|
||||
// Amount is the quantity to give (0 = normal max).
|
||||
AHexenArmor *copy = Spawn<AHexenArmor> ();
|
||||
copy->AddArmorToSlot (other, health, Amount);
|
||||
GoAwayAndDie ();
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: CreateTossable
|
||||
//
|
||||
// Since this isn't really a single item, you can't drop it. Ever.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AHexenArmor::CreateTossable ()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: HandlePickup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AHexenArmor::HandlePickup (AInventory *item)
|
||||
{
|
||||
if (item->IsKindOf (RUNTIME_CLASS(AHexenArmor)))
|
||||
{
|
||||
if (AddArmorToSlot (Owner, item->health, item->Amount))
|
||||
{
|
||||
item->ItemFlags |= IF_PICKUPGOOD;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: AddArmorToSlot
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount)
|
||||
{
|
||||
APlayerPawn *ppawn;
|
||||
double hits;
|
||||
|
||||
if (actor->player != NULL)
|
||||
{
|
||||
ppawn = static_cast<APlayerPawn *>(actor);
|
||||
}
|
||||
else
|
||||
{
|
||||
ppawn = NULL;
|
||||
}
|
||||
|
||||
if (slot < 0 || slot > 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (amount <= 0)
|
||||
{
|
||||
hits = SlotsIncrement[slot];
|
||||
if (Slots[slot] < hits)
|
||||
{
|
||||
Slots[slot] = hits;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hits = amount * 5;
|
||||
auto total = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
|
||||
auto max = SlotsIncrement[0] + SlotsIncrement[1] + SlotsIncrement[2] + SlotsIncrement[3] + Slots[4] + 4 * 5;
|
||||
if (total < max)
|
||||
{
|
||||
Slots[slot] += hits;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: AbsorbDamage
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
|
||||
{
|
||||
if (!DamageTypeDefinition::IgnoreArmor(damageType))
|
||||
{
|
||||
double savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
|
||||
|
||||
if (savedPercent)
|
||||
{ // armor absorbed some damage
|
||||
if (savedPercent > 100)
|
||||
{
|
||||
savedPercent = 100;
|
||||
}
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (Slots[i])
|
||||
{
|
||||
// 300 damage always wipes out the armor unless some was added
|
||||
// with the dragon skin bracers.
|
||||
if (damage < 10000)
|
||||
{
|
||||
Slots[i] -= damage * SlotsIncrement[i] / 300.;
|
||||
if (Slots[i] < 2)
|
||||
{
|
||||
Slots[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Slots[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
int saved = int(damage * savedPercent / 100.);
|
||||
if (saved > savedPercent*2)
|
||||
{
|
||||
saved = int(savedPercent*2);
|
||||
}
|
||||
newdamage -= saved;
|
||||
damage = newdamage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: DepleteOrDestroy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AHexenArmor::DepleteOrDestroy()
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Slots[i] = 0;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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<AKey*>(GetDefaultByType(mi))->KeyNumber == 0)
|
||||
GetDefaultByType(mi)->special1 == 0)
|
||||
{
|
||||
static_cast<AKey*>(GetDefaultByType(mi))->KeyNumber=++currentnumber;
|
||||
GetDefaultByType(mi)->special1 = ++currentnumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -387,14 +382,15 @@ static void ParseLock(FScanner &sc)
|
|||
static void ClearLocks()
|
||||
{
|
||||
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<AKey*>(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
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
** a_weaponpieces.cpp
|
||||
** Implements generic weapon pieces
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006-2016 Cheistoph Oelckers
|
||||
** Copyright 2006-2016 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "a_pickups.h"
|
||||
#include "a_weaponpiece.h"
|
||||
#include "doomstat.h"
|
||||
#include "serializer.h"
|
||||
|
||||
IMPLEMENT_CLASS(AWeaponHolder, false, false)
|
||||
|
||||
DEFINE_FIELD(AWeaponHolder, PieceMask);
|
||||
DEFINE_FIELD(AWeaponHolder, PieceWeapon);
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AWeaponHolder::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
arc("piecemask", PieceMask)
|
||||
("pieceweapon", PieceWeapon);
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(AWeaponPiece, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(AWeaponPiece)
|
||||
IMPLEMENT_POINTER(FullWeapon)
|
||||
IMPLEMENT_POINTER(WeaponClass)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AWeaponPiece::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (AWeaponPiece*)GetDefault();
|
||||
arc("weaponclass", WeaponClass, def->WeaponClass)
|
||||
("fullweapon", FullWeapon)
|
||||
("piecevalue", PieceValue, def->PieceValue);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TryPickupWeaponPiece
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool AWeaponPiece::TryPickupRestricted (AActor *&toucher)
|
||||
{
|
||||
// Wrong class, but try to pick up for ammo
|
||||
if (CallShouldStay())
|
||||
{ // Can't pick up weapons for other classes in coop netplay
|
||||
return false;
|
||||
}
|
||||
|
||||
AWeapon * Defaults=(AWeapon*)GetDefaultByType(WeaponClass);
|
||||
|
||||
bool gaveSome = !!(toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1) +
|
||||
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2));
|
||||
|
||||
if (gaveSome)
|
||||
{
|
||||
GoAwayAndDie ();
|
||||
}
|
||||
return gaveSome;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TryPickupWeaponPiece
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool AWeaponPiece::TryPickup (AActor *&toucher)
|
||||
{
|
||||
AInventory * inv;
|
||||
AWeaponHolder * hold=NULL;
|
||||
bool shouldStay = PrivateShouldStay ();
|
||||
int gaveAmmo;
|
||||
AWeapon * Defaults=(AWeapon*)GetDefaultByType(WeaponClass);
|
||||
|
||||
FullWeapon=NULL;
|
||||
for(inv=toucher->Inventory;inv;inv=inv->Inventory)
|
||||
{
|
||||
if (inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder)))
|
||||
{
|
||||
hold=static_cast<AWeaponHolder*>(inv);
|
||||
|
||||
if (hold->PieceWeapon==WeaponClass) break;
|
||||
hold=NULL;
|
||||
}
|
||||
}
|
||||
if (!hold)
|
||||
{
|
||||
hold=static_cast<AWeaponHolder*>(Spawn(RUNTIME_CLASS(AWeaponHolder)));
|
||||
hold->BecomeItem();
|
||||
hold->AttachToOwner(toucher);
|
||||
hold->PieceMask=0;
|
||||
hold->PieceWeapon=WeaponClass;
|
||||
}
|
||||
|
||||
|
||||
if (shouldStay)
|
||||
{
|
||||
// Cooperative net-game
|
||||
if (hold->PieceMask & PieceValue)
|
||||
{
|
||||
// Already has the piece
|
||||
return false;
|
||||
}
|
||||
toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1);
|
||||
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2);
|
||||
}
|
||||
else
|
||||
{ // Deathmatch or singleplayer game
|
||||
gaveAmmo = toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1) +
|
||||
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2);
|
||||
|
||||
if (hold->PieceMask & PieceValue)
|
||||
{
|
||||
// Already has the piece, check if mana needed
|
||||
if (!gaveAmmo) return false;
|
||||
GoAwayAndDie();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
hold->PieceMask |= PieceValue;
|
||||
|
||||
// Check if weapon assembled
|
||||
if (hold->PieceMask== (1<<Defaults->health)-1)
|
||||
{
|
||||
if (!toucher->FindInventory (WeaponClass))
|
||||
{
|
||||
FullWeapon= static_cast<AWeapon*>(Spawn(WeaponClass));
|
||||
|
||||
// The weapon itself should not give more ammo to the player!
|
||||
FullWeapon->AmmoGive1=0;
|
||||
FullWeapon->AmmoGive2=0;
|
||||
FullWeapon->AttachToOwner(toucher);
|
||||
FullWeapon->AmmoGive1=Defaults->AmmoGive1;
|
||||
FullWeapon->AmmoGive2=Defaults->AmmoGive2;
|
||||
}
|
||||
}
|
||||
GoAwayAndDie();
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeaponPiece::ShouldStay ()
|
||||
{
|
||||
return PrivateShouldStay ();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeaponPiece::PrivateShouldStay ()
|
||||
{
|
||||
// We want a weapon piece to behave like a weapon, so follow the exact
|
||||
// same logic as weapons when deciding whether or not to stay.
|
||||
if (((multiplayer &&
|
||||
(!deathmatch && !alwaysapplydmflags)) || (dmflags & DF_WEAPONS_STAY)) &&
|
||||
!(flags&MF_DROPPED))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// PickupMessage
|
||||
//
|
||||
// Returns the message to print when this actor is picked up.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString AWeaponPiece::PickupMessage ()
|
||||
{
|
||||
if (FullWeapon)
|
||||
{
|
||||
return FullWeapon->PickupMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Super::PickupMessage();
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// DoPlayPickupSound
|
||||
//
|
||||
// Plays a sound when this actor is picked up.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AWeaponPiece::PlayPickupSound (AActor *toucher)
|
||||
{
|
||||
if (FullWeapon)
|
||||
{
|
||||
FullWeapon->PlayPickupSound(toucher);
|
||||
}
|
||||
else
|
||||
{
|
||||
Super::PlayPickupSound(toucher);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#pragma once
|
||||
#include "a_pickups.h"
|
||||
#include "a_weapons.h"
|
||||
|
||||
class AWeaponPiece : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (AWeaponPiece, AInventory)
|
||||
HAS_OBJECT_POINTERS
|
||||
protected:
|
||||
bool PrivateShouldStay ();
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual bool TryPickup (AActor *&toucher) override;
|
||||
virtual bool TryPickupRestricted (AActor *&toucher) override;
|
||||
virtual bool ShouldStay () override;
|
||||
virtual FString PickupMessage () override;
|
||||
virtual void PlayPickupSound (AActor *toucher) override;
|
||||
|
||||
int PieceValue;
|
||||
PClassActor *WeaponClass;
|
||||
TObjPtr<AWeapon> FullWeapon;
|
||||
};
|
||||
|
||||
// an internal class to hold the information for player class independent weapon piece handling
|
||||
// [BL] Needs to be available for SBarInfo to check weaponpieces
|
||||
class AWeaponHolder : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (AWeaponHolder, AInventory)
|
||||
|
||||
public:
|
||||
int PieceMask;
|
||||
PClassActor * PieceWeapon;
|
||||
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
};
|
|
@ -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<AAmmo *>(other->FindInventory (ammotype));
|
||||
ammo = other->FindInventory (ammotype);
|
||||
if (ammo == NULL)
|
||||
{
|
||||
ammo = static_cast<AAmmo *>(Spawn (ammotype));
|
||||
ammo = static_cast<AInventory *>(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))
|
||||
{
|
||||
|
|
|
@ -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<AAmmo> Ammo1, Ammo2;
|
||||
TObjPtr<AInventory> Ammo1, Ammo2;
|
||||
TObjPtr<AWeapon> 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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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<AHexenArmor>();
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<ABasicArmor>();
|
||||
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;
|
||||
|
||||
|
|
|
@ -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<AHexenArmor>();
|
||||
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<AKey *>(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<AHexenArmor>();
|
||||
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<PFunction*>(RUNTIME_CLASS(APlayerPawn)->Symbols.FindSymbol("GetEffectTicsForItem", false))->Variants[0].Implementation;
|
||||
if (func == nullptr) func = PClass::FindFunction(NAME_PlayerPawn, "GetEffectTicsForItem");
|
||||
VMValue params[] = { statusBar->CPlayer->mo, inventoryItem };
|
||||
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<PFunction*>(RUNTIME_CLASS(APlayerPawn)->Symbols.FindSymbol("GetEffectTicsForItem", false))->Variants[0].Implementation;
|
||||
if (func == nullptr) func = PClass::FindFunction(NAME_PlayerPawn, "GetEffectTicsForItem");
|
||||
VMValue params[] = { statusBar->CPlayer->mo, data.inventoryItem };
|
||||
VMReturn ret[2];
|
||||
int ival;
|
||||
|
@ -2840,16 +2844,17 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
case SAVEPERCENT:
|
||||
{
|
||||
double add = 0;
|
||||
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>();
|
||||
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<AWeaponHolder*>(inv);
|
||||
if(hold->PieceWeapon == weapon)
|
||||
if(inv->PointerVar<PClass>("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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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<PClassActor *> 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<PClassActor *>(ti);
|
||||
AKey *key = (AKey*)GetDefaultByType(tia);
|
||||
AInventory *key = (AInventory*)(GetDefaultByType(tia));
|
||||
|
||||
if (key->Icon.isValid() && key->KeyNumber>0)
|
||||
if (key->Icon.isValid() && key->special1 > 0)
|
||||
{
|
||||
KeyTypes.Push(tia);
|
||||
}
|
||||
|
@ -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<AAmmo*>(CPlayer->mo->FindInventory(type));
|
||||
AAmmo * inv = nullptr == ammoitem
|
||||
? static_cast<AAmmo*>(GetDefaultByType(type))
|
||||
auto ammoitem = CPlayer->mo->FindInventory(type);
|
||||
auto inv = nullptr == ammoitem
|
||||
? static_cast<AInventory*>(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<ABasicArmor>(),
|
||||
CPlayer->mo->FindInventory<AHexenArmor>(), 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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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<ABasicArmor>();
|
||||
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<ABasicArmor>();
|
||||
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++;
|
||||
}
|
||||
|
|
|
@ -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] =
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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>((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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<ABasicArmor>();
|
||||
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<PClassActor *>(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)
|
||||
|
|
|
@ -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<ABasicArmorBonus::MetaClass>(PClass::FindClass("ArmorBonus"));
|
||||
armorbonustype = PClass::FindActor("ArmorBonus");
|
||||
}
|
||||
if (armorbonustype != NULL)
|
||||
{
|
||||
assert(armorbonustype->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)));
|
||||
ABasicArmorBonus *armorbonus = static_cast<ABasicArmorBonus *>(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<AInventory*>(armorbonus)->CallTryPickup(self))
|
||||
{
|
||||
armorbonus->Destroy ();
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<AAmmo *>(inv)->DropAmount;
|
||||
int amount = inv->IntVar("DropAmount");
|
||||
if (amount <= 0)
|
||||
{
|
||||
amount = MAX(1, int(inv->Amount * dropammofactor));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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<ABasicArmorPickup*>(item)->SaveAmount *= amount;
|
||||
}
|
||||
else if (type->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus)))
|
||||
{
|
||||
static_cast<ABasicArmorBonus*>(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<AHexenArmor *> (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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<AKey *>(Spawn(static_cast<PClassActor *>(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<ABasicArmor*>(item)->SavePercent = static_cast<ABasicArmor*>(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<AHexenArmor*>(item)->Slots[0] = static_cast<AHexenArmor*>(defitem)->Slots[0];
|
||||
static_cast<AHexenArmor*>(item)->Slots[1] = static_cast<AHexenArmor*>(defitem)->Slots[1];
|
||||
static_cast<AHexenArmor*>(item)->Slots[2] = static_cast<AHexenArmor*>(defitem)->Slots[2];
|
||||
static_cast<AHexenArmor*>(item)->Slots[3] = static_cast<AHexenArmor*>(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<AHexenArmor>();
|
||||
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<ABasicArmor> ();
|
||||
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<PClassPlayerPawn>(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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<PClassActor *>(cls);
|
||||
}
|
||||
static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false)
|
||||
static AInventory::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false)
|
||||
{
|
||||
return static_cast<AAmmo::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AAmmo), optional));
|
||||
return static_cast<PClassInventory *>(FindClassTentative(name, PClass::FindActor(NAME_Ammo), optional));
|
||||
}
|
||||
static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false)
|
||||
{
|
||||
|
@ -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<PField>(cls->Symbols.FindSymbol(field, true));
|
||||
if (sym && (sym->Type == type || PointerCheck(sym->Type, type)))
|
||||
{
|
||||
return (((char*)obj) + sym->Offset);
|
||||
}
|
||||
I_Error("Variable %s of type %s not found in %s\n", field.GetChars(), type->DescriptiveName(), cls->TypeName.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T &TypedScriptVar(DObject *obj, PClass *cls, FName field, PType *type)
|
||||
{
|
||||
return *(T*)ScriptVar(obj, cls, field, type);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Info Property handlers
|
||||
|
@ -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<PClassActor*>(defaults, info, NAME_PowerupType, NewClassPointer(RUNTIME_CLASS(AActor))) = cls;
|
||||
defaults->PointerVar<PClassActor>(NAME_PowerupType) = cls;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3018,7 +2837,7 @@ DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile)
|
|||
DEFINE_SCRIPTED_PROPERTY(playerclass, S, PowerMorph)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_PlayerClass, NewClassPointer(RUNTIME_CLASS(APlayerPawn))) = FindClassTentativePlayerPawn(str, bag.fromDecorate);
|
||||
defaults->PointerVar<PClassActor>(NAME_PlayerClass) = FindClassTentativePlayerPawn(str, bag.fromDecorate);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3027,7 +2846,7 @@ DEFINE_SCRIPTED_PROPERTY(playerclass, S, PowerMorph)
|
|||
DEFINE_SCRIPTED_PROPERTY(morphstyle, M, PowerMorph)
|
||||
{
|
||||
PROP_INT_PARM(i, 0);
|
||||
TypedScriptVar<int>(defaults, bag.Info, NAME_MorphStyle, TypeSInt32) = i;
|
||||
defaults->IntVar(NAME_MorphStyle) = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3036,7 +2855,7 @@ DEFINE_SCRIPTED_PROPERTY(morphstyle, M, PowerMorph)
|
|||
DEFINE_SCRIPTED_PROPERTY(morphflash, S, PowerMorph)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_MorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
|
||||
defaults->PointerVar<PClassActor>(NAME_MorphFlash) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3045,7 +2864,7 @@ DEFINE_SCRIPTED_PROPERTY(morphflash, S, PowerMorph)
|
|||
DEFINE_SCRIPTED_PROPERTY(unmorphflash, S, PowerMorph)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_UnMorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
|
||||
defaults->PointerVar<PClassActor>(NAME_UnMorphFlash) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1380,16 +1380,24 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Proper
|
|||
TArray<PField *> fields;
|
||||
ZCC_Identifier *id = (ZCC_Identifier *)p->Body;
|
||||
|
||||
do
|
||||
if (FName(p->NodeName) == FName("prefix") && Wads.GetLumpFile(Lump) == 0)
|
||||
{
|
||||
auto f = dyn_cast<PField>(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<PField>(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.
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Actor> GetParentAmmo ();
|
||||
//===========================================================================
|
||||
//
|
||||
// AAmmo :: GetParentAmmo
|
||||
//
|
||||
// Returns the least-derived ammo type that this ammo is a descendant of.
|
||||
// That is, if this ammo is an immediate subclass of Ammo, then this ammo's
|
||||
// type is returned. If this ammo's superclass is not Ammo, then this
|
||||
// function travels up the inheritance chain until it finds a type that is
|
||||
// an immediate subclass of Ammo and returns that.
|
||||
//
|
||||
// The intent of this is that all unique ammo types will be immediate
|
||||
// subclasses of Ammo. To make different pickups with different ammo amounts,
|
||||
// you subclass the type of ammo you want a different amount for and edit
|
||||
// that.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
Class<Ammo> GetParentAmmo ()
|
||||
{
|
||||
class<Object> type = GetClass();
|
||||
|
||||
while (type.GetParentClass() != "Ammo" && type.GetParentClass() != NULL)
|
||||
{
|
||||
type = type.GetParentClass();
|
||||
}
|
||||
return (class<Ammo>)(type);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -113,7 +144,7 @@ class Ammo : Inventory native
|
|||
}
|
||||
|
||||
let type = GetParentAmmo();
|
||||
if (GetClass() == type)
|
||||
if (GetClass() != type && type != null)
|
||||
{
|
||||
if (!GoAway ())
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
225
wadsrc/static/zscript/inventory/weaponpiece.txt
Normal file
225
wadsrc/static/zscript/inventory/weaponpiece.txt
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
** a_weaponpieces.cpp
|
||||
** Implements generic weapon pieces
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006-2016 Cheistoph Oelckers
|
||||
** Copyright 2006-2016 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
class WeaponHolder : Inventory
|
||||
{
|
||||
int PieceMask;
|
||||
Class<Weapon> PieceWeapon;
|
||||
|
||||
Default
|
||||
{
|
||||
+NOBLOCKMAP
|
||||
+NOSECTOR
|
||||
+INVENTORY.UNDROPPABLE
|
||||
}
|
||||
}
|
||||
|
||||
class WeaponPiece : Inventory
|
||||
{
|
||||
Default
|
||||
{
|
||||
+WEAPONSPAWN;
|
||||
}
|
||||
|
||||
int PieceValue;
|
||||
Class<Weapon> WeaponClass;
|
||||
Weapon FullWeapon;
|
||||
|
||||
property number: PieceValue;
|
||||
property weapon: WeaponClass;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TryPickupWeaponPiece
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
override bool TryPickupRestricted (in out Actor toucher)
|
||||
{
|
||||
// Wrong class, but try to pick up for ammo
|
||||
if (ShouldStay())
|
||||
{ // Can't pick up weapons for other classes in coop netplay
|
||||
return false;
|
||||
}
|
||||
|
||||
let Defaults = GetDefaultByType(WeaponClass);
|
||||
|
||||
bool gaveSome = !!(toucher.GiveAmmo (Defaults.AmmoType1, Defaults.AmmoGive1) +
|
||||
toucher.GiveAmmo (Defaults.AmmoType2, Defaults.AmmoGive2));
|
||||
|
||||
if (gaveSome)
|
||||
{
|
||||
GoAwayAndDie ();
|
||||
}
|
||||
return gaveSome;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TryPickupWeaponPiece
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
override bool TryPickup (in out Actor toucher)
|
||||
{
|
||||
Inventory item;
|
||||
WeaponHolder hold = NULL;
|
||||
bool shouldStay = ShouldStay ();
|
||||
int gaveAmmo;
|
||||
let Defaults = GetDefaultByType(WeaponClass);
|
||||
|
||||
FullWeapon = NULL;
|
||||
for(item=toucher.Inv; item; item=item.Inv)
|
||||
{
|
||||
hold = WeaponHolder(item);
|
||||
if (hold != null)
|
||||
{
|
||||
if (hold.PieceWeapon == WeaponClass)
|
||||
{
|
||||
break;
|
||||
}
|
||||
hold = NULL;
|
||||
}
|
||||
}
|
||||
if (!hold)
|
||||
{
|
||||
hold = WeaponHolder(Spawn("WeaponHolder"));
|
||||
hold.BecomeItem();
|
||||
hold.AttachToOwner(toucher);
|
||||
hold.PieceMask = 0;
|
||||
hold.PieceWeapon = WeaponClass;
|
||||
}
|
||||
|
||||
int pieceval = 1 << (PieceValue - 1);
|
||||
if (shouldStay)
|
||||
{
|
||||
// Cooperative net-game
|
||||
if (hold.PieceMask & pieceval)
|
||||
{
|
||||
// Already has the piece
|
||||
return false;
|
||||
}
|
||||
toucher.GiveAmmo (Defaults.AmmoType1, Defaults.AmmoGive1);
|
||||
toucher.GiveAmmo (Defaults.AmmoType2, Defaults.AmmoGive2);
|
||||
}
|
||||
else
|
||||
{ // Deathmatch or singleplayer game
|
||||
gaveAmmo = toucher.GiveAmmo (Defaults.AmmoType1, Defaults.AmmoGive1) +
|
||||
toucher.GiveAmmo (Defaults.AmmoType2, Defaults.AmmoGive2);
|
||||
|
||||
if (hold.PieceMask & pieceval)
|
||||
{
|
||||
// Already has the piece, check if mana needed
|
||||
if (!gaveAmmo) return false;
|
||||
GoAwayAndDie();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
hold.PieceMask |= pieceval;
|
||||
|
||||
// Check if weapon assembled
|
||||
if (hold.PieceMask == (1 << Defaults.health) - 1)
|
||||
{
|
||||
if (!toucher.FindInventory (WeaponClass))
|
||||
{
|
||||
FullWeapon= Weapon(Spawn(WeaponClass));
|
||||
|
||||
// The weapon itself should not give more ammo to the player.
|
||||
FullWeapon.AmmoGive1 = 0;
|
||||
FullWeapon.AmmoGive2 = 0;
|
||||
FullWeapon.AttachToOwner(toucher);
|
||||
FullWeapon.AmmoGive1 = Defaults.AmmoGive1;
|
||||
FullWeapon.AmmoGive2 = Defaults.AmmoGive2;
|
||||
}
|
||||
}
|
||||
GoAwayAndDie();
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override bool ShouldStay ()
|
||||
{
|
||||
// We want a weapon piece to behave like a weapon, so follow the exact
|
||||
// same logic as weapons when deciding whether or not to stay.
|
||||
return (((multiplayer &&
|
||||
(!deathmatch && !alwaysapplydmflags)) || sv_weaponstay) && !bDropped);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// PickupMessage
|
||||
//
|
||||
// Returns the message to print when this actor is picked up.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override String PickupMessage ()
|
||||
{
|
||||
if (FullWeapon)
|
||||
{
|
||||
return FullWeapon.PickupMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Super.PickupMessage();
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// DoPlayPickupSound
|
||||
//
|
||||
// Plays a sound when this actor is picked up.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void PlayPickupSound (Actor toucher)
|
||||
{
|
||||
if (FullWeapon)
|
||||
{
|
||||
FullWeapon.PlayPickupSound(toucher);
|
||||
}
|
||||
else
|
||||
{
|
||||
Super.PlayPickupSound(toucher);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -104,27 +104,6 @@ class WeaponGiver : Weapon native
|
|||
}
|
||||
}
|
||||
|
||||
class WeaponHolder : Inventory native
|
||||
{
|
||||
native int PieceMask;
|
||||
native Class<Actor> PieceWeapon;
|
||||
|
||||
Default
|
||||
{
|
||||
+NOBLOCKMAP
|
||||
+NOSECTOR
|
||||
+INVENTORY.UNDROPPABLE
|
||||
}
|
||||
}
|
||||
|
||||
class WeaponPiece : Inventory native
|
||||
{
|
||||
Default
|
||||
{
|
||||
+WEAPONSPAWN;
|
||||
}
|
||||
}
|
||||
|
||||
struct WeaponSlots native
|
||||
{
|
||||
native bool, int, int LocateWeapon(class<Weapon> weap);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ class PlayerPawn : Actor native
|
|||
native void CheckWeaponSwitch(class<Inventory> item);
|
||||
}
|
||||
|
||||
class PlayerChunk : PlayerPawn native
|
||||
class PlayerChunk : PlayerPawn
|
||||
{
|
||||
Default
|
||||
{
|
||||
|
|
|
@ -157,8 +157,8 @@ extend class PlayerPawn
|
|||
{
|
||||
if (AllActorClasses[i] is "Key")
|
||||
{
|
||||
readonly<Key> keyitem = GetDefaultByType ((class<Key>)(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue