- copied inventory files to their own folder.

It's about time this stuff is getting cleaned up seriously. Both a_pickups.cpp and a_artifacts.cpp are so overstuffed that it has become a chore finding stuff in there.
This commit is contained in:
Christoph Oelckers 2016-11-30 10:28:02 +01:00
commit 014e04ce82
13 changed files with 11 additions and 9 deletions

View file

@ -1,583 +0,0 @@
#include <assert.h>
#include "info.h"
#include "gi.h"
#include "a_pickups.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)
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.
DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors;
if (df != NULL)
{
damage = newdamage = df->Apply(damageType, damage);
}
}
if (Inventory != NULL)
{
Inventory->AbsorbDamage (damage, damageType, newdamage);
}
}
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;
}
//===========================================================================
//
// ABasicArmorBonus
//
//===========================================================================
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;
}
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;
}
}
if (Inventory != NULL)
{
Inventory->AbsorbDamage (damage, damageType, newdamage);
}
}
void AHexenArmor::DepleteOrDestroy()
{
for (int i = 0; i < 4; i++)
{
Slots[i] = 0;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,298 +0,0 @@
#ifndef __A_ARTIFACTS_H__
#define __A_ARTIFACTS_H__
#include "a_pickups.h"
class player_t;
// A powerup is a pseudo-inventory item that applies an effect to its
// owner while it is present.
class APowerup : public AInventory
{
DECLARE_CLASS (APowerup, AInventory)
public:
virtual void Tick ();
virtual void Destroy () override;
virtual bool HandlePickup (AInventory *item);
virtual AInventory *CreateCopy (AActor *other);
virtual AInventory *CreateTossable ();
virtual void Serialize(FSerializer &arc);
virtual void OwnerDied ();
virtual bool GetNoTeleportFreeze();
virtual PalEntry GetBlend ();
virtual bool DrawPowerup (int x, int y);
int EffectTics;
PalEntry BlendColor;
FNameNoInit Mode;
double Strength;
protected:
virtual void InitEffect ();
virtual void DoEffect ();
virtual void EndEffect ();
friend void EndAllPowerupEffects(AInventory *item);
friend void InitAllPowerupEffects(AInventory *item);
};
class PClassPowerupGiver: public PClassInventory
{
DECLARE_CLASS(PClassPowerupGiver, PClassInventory)
protected:
public:
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
};
// An artifact is an item that gives the player a powerup when activated.
class APowerupGiver : public AInventory
{
DECLARE_CLASS_WITH_META (APowerupGiver, AInventory, PClassPowerupGiver)
public:
virtual bool Use (bool pickup);
virtual void Serialize(FSerializer &arc);
PClassActor *PowerupType;
int EffectTics; // Non-0 to override the powerup's default tics
PalEntry BlendColor; // Non-0 to override the powerup's default blend
FNameNoInit Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility
double Strength; // Meaning depends on powerup - currently used only by Invisibility
};
class APowerInvulnerable : public APowerup
{
DECLARE_CLASS (APowerInvulnerable, APowerup)
protected:
void InitEffect ();
void DoEffect ();
void EndEffect ();
int AlterWeaponSprite (visstyle_t *vis);
};
class APowerStrength : public APowerup
{
DECLARE_CLASS (APowerStrength, APowerup)
public:
PalEntry GetBlend ();
protected:
void InitEffect ();
void Tick ();
bool HandlePickup (AInventory *item);
};
class APowerInvisibility : public APowerup
{
DECLARE_CLASS (APowerInvisibility, APowerup)
protected:
bool HandlePickup (AInventory *item);
void InitEffect ();
void DoEffect ();
void EndEffect ();
int AlterWeaponSprite (visstyle_t *vis);
};
class APowerIronFeet : public APowerup
{
DECLARE_CLASS (APowerIronFeet, APowerup)
public:
void AbsorbDamage (int damage, FName damageType, int &newdamage);
void DoEffect ();
};
class APowerMask : public APowerIronFeet
{
DECLARE_CLASS (APowerMask, APowerIronFeet)
public:
void AbsorbDamage (int damage, FName damageType, int &newdamage);
void DoEffect ();
};
class APowerLightAmp : public APowerup
{
DECLARE_CLASS (APowerLightAmp, APowerup)
protected:
void DoEffect ();
void EndEffect ();
};
class APowerTorch : public APowerLightAmp
{
DECLARE_CLASS (APowerTorch, APowerLightAmp)
public:
virtual void Serialize(FSerializer &arc);
protected:
void DoEffect ();
int NewTorch, NewTorchDelta;
};
class APowerFlight : public APowerup
{
DECLARE_CLASS (APowerFlight, APowerup)
public:
bool DrawPowerup (int x, int y);
virtual void Serialize(FSerializer &arc);
protected:
void InitEffect ();
void Tick ();
void EndEffect ();
private:
bool HitCenterFrame;
};
class APowerWeaponLevel2 : public APowerup
{
DECLARE_CLASS (APowerWeaponLevel2, APowerup)
protected:
void InitEffect ();
void EndEffect ();
};
class APowerSpeed : public APowerup
{
DECLARE_CLASS (APowerSpeed, APowerup)
protected:
void DoEffect ();
virtual void Serialize(FSerializer &arc);
double GetSpeedFactor();
public:
int SpeedFlags;
};
#define PSF_NOTRAIL 1
class APowerMinotaur : public APowerup
{
DECLARE_CLASS (APowerMinotaur, APowerup)
};
class APowerScanner : public APowerup
{
DECLARE_CLASS (APowerScanner, APowerup)
};
class APowerTargeter : public APowerup
{
DECLARE_CLASS (APowerTargeter, APowerup)
protected:
void InitEffect ();
void DoEffect ();
void EndEffect ();
void PositionAccuracy ();
void Travelled ();
void AttachToOwner(AActor *other);
bool HandlePickup(AInventory *item);
};
class APowerFrightener : public APowerup
{
DECLARE_CLASS (APowerFrightener, APowerup)
protected:
void InitEffect ();
void EndEffect ();
};
class APowerBuddha : public APowerup
{
DECLARE_CLASS (APowerBuddha, APowerup)
protected:
void InitEffect ();
void EndEffect ();
};
class APowerTimeFreezer : public APowerup
{
DECLARE_CLASS( APowerTimeFreezer, APowerup )
protected:
void InitEffect( );
void DoEffect( );
void EndEffect( );
};
class APowerDamage : public APowerup
{
DECLARE_CLASS( APowerDamage, APowerup )
protected:
void InitEffect ();
void EndEffect ();
virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive);
};
class APowerProtection : public APowerup
{
DECLARE_CLASS( APowerProtection, APowerup )
protected:
void InitEffect ();
void EndEffect ();
virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive);
};
class APowerDrain : public APowerup
{
DECLARE_CLASS( APowerDrain, APowerup )
protected:
void InitEffect( );
void EndEffect( );
};
class APowerRegeneration : public APowerup
{
DECLARE_CLASS( APowerRegeneration, APowerup )
protected:
void DoEffect();
};
class APowerHighJump : public APowerup
{
DECLARE_CLASS( APowerHighJump, APowerup )
protected:
void InitEffect( );
void EndEffect( );
};
class APowerDoubleFiringSpeed : public APowerup
{
DECLARE_CLASS( APowerDoubleFiringSpeed, APowerup )
protected:
void InitEffect( );
void EndEffect( );
};
class APowerInfiniteAmmo : public APowerup
{
DECLARE_CLASS( APowerInfiniteAmmo, APowerup )
protected:
void InitEffect( );
void EndEffect( );
};
class APowerMorph : public APowerup
{
DECLARE_CLASS( APowerMorph, APowerup )
public:
virtual void Serialize(FSerializer &arc);
void SetNoCallUndoMorph() { bInUndoMorph = true; }
// Variables
PClassPlayerPawn *PlayerClass;
PClassActor *MorphFlash, *UnMorphFlash;
int MorphStyle;
player_t *MorphedPlayer;
bool bInUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively
protected:
void InitEffect ();
void EndEffect ();
};
#endif //__A_ARTIFACTS_H__

View file

@ -1,529 +0,0 @@
#include "a_keys.h"
#include "tarray.h"
#include "gi.h"
#include "gstrings.h"
#include "d_player.h"
#include "c_console.h"
#include "s_sound.h"
#include "sc_man.h"
#include "v_palette.h"
#include "w_wad.h"
#include "doomstat.h"
#include "v_font.h"
struct OneKey
{
PClassActor *key;
int count;
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;
for (item = owner->Inventory; item != NULL; item = item->Inventory)
{
if (item->IsA(key))
{
return true;
}
else if (item->GetSpecies() == key->TypeName)
{
return true;
}
}
return false;
}
}
};
struct Keygroup
{
TArray<OneKey> anykeylist;
bool check(AActor *owner)
{
for(unsigned int i=0;i<anykeylist.Size();i++)
{
if (anykeylist[i].check(owner)) return true;
}
return false;
}
};
struct Lock
{
TArray<Keygroup *> keylist;
TArray<FSoundID> locksound;
FString Message;
FString RemoteMsg;
int rgb;
Lock()
{
rgb=0;
}
~Lock()
{
for(unsigned int i=0;i<keylist.Size();i++) delete keylist[i];
keylist.Clear();
}
bool check(AActor * owner)
{
// An empty key list means that any key will do
if (!keylist.Size())
{
for (AInventory * item = owner->Inventory; item != NULL; item = item->Inventory)
{
if (item->IsKindOf (RUNTIME_CLASS(AKey)))
{
return true;
}
}
return false;
}
else for(unsigned int i=0;i<keylist.Size();i++)
{
if (!keylist[i]->check(owner)) return false;
}
return true;
}
};
static Lock *locks[256]; // all valid locks
static bool keysdone=false; // have the locks been initialized?
static int currentnumber; // number to be assigned to next key
static bool ignorekey; // set to true when the current lock is not being used
static void ClearLocks();
static const char * keywords_lock[]={
"ANY",
"MESSAGE",
"REMOTEMESSAGE",
"MAPCOLOR",
"LOCKEDSOUND",
NULL
};
//===========================================================================
//
//
//===========================================================================
static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc)
{
if (mi)
{
// Any inventory item can be used to unlock a door
if (mi->IsDescendantOf(RUNTIME_CLASS(AInventory)))
{
OneKey k = {mi,1};
keygroup->anykeylist.Push (k);
//... but only keys get key numbers!
if (mi->IsDescendantOf(RUNTIME_CLASS(AKey)))
{
if (!ignorekey &&
static_cast<AKey*>(GetDefaultByType(mi))->KeyNumber == 0)
{
static_cast<AKey*>(GetDefaultByType(mi))->KeyNumber=++currentnumber;
}
}
}
else
{
sc.ScriptError("'%s' is not an inventory item", sc.String);
}
}
else
{
sc.ScriptError("Unknown item '%s'", sc.String);
}
}
//===========================================================================
//
//
//===========================================================================
static Keygroup *ParseKeygroup(FScanner &sc)
{
Keygroup *keygroup;
PClassActor *mi;
sc.MustGetStringName("{");
keygroup = new Keygroup;
while (!sc.CheckString("}"))
{
sc.MustGetString();
mi = PClass::FindActor(sc.String);
AddOneKey(keygroup, mi, sc);
}
if (keygroup->anykeylist.Size() == 0)
{
delete keygroup;
return NULL;
}
keygroup->anykeylist.ShrinkToFit();
return keygroup;
}
//===========================================================================
//
//
//===========================================================================
static void PrintMessage (const char *str)
{
if (str != NULL)
{
if (str[0]=='$')
{
str = GStrings(str+1);
}
C_MidPrint (SmallFont, str);
}
}
//===========================================================================
//
//
//===========================================================================
static void ParseLock(FScanner &sc)
{
int i,r,g,b;
int keynum;
Lock sink;
Lock *lock = &sink;
Keygroup *keygroup;
PClassActor *mi;
sc.MustGetNumber();
keynum = sc.Number;
sc.MustGetString();
if (!sc.Compare("{"))
{
if (!CheckGame(sc.String, false)) keynum = -1;
sc.MustGetStringName("{");
}
ignorekey = true;
if (keynum > 0 && keynum <= 255)
{
lock = new Lock;
if (locks[keynum])
{
delete locks[keynum];
}
locks[keynum] = lock;
locks[keynum]->locksound.Push("*keytry");
locks[keynum]->locksound.Push("misc/keytry");
ignorekey=false;
}
else if (keynum != -1)
{
sc.ScriptError("Lock index %d out of range", keynum);
}
while (!sc.CheckString("}"))
{
sc.MustGetString();
switch(i = sc.MatchString(keywords_lock))
{
case 0: // Any
keygroup = ParseKeygroup(sc);
if (keygroup)
{
lock->keylist.Push(keygroup);
}
break;
case 1: // message
sc.MustGetString();
lock->Message = sc.String;
break;
case 2: // remotemsg
sc.MustGetString();
lock->RemoteMsg = sc.String;
break;
case 3: // mapcolor
sc.MustGetNumber();
r = sc.Number;
sc.MustGetNumber();
g = sc.Number;
sc.MustGetNumber();
b = sc.Number;
lock->rgb = MAKERGB(r,g,b);
break;
case 4: // locksound
lock->locksound.Clear();
for (;;)
{
sc.MustGetString();
lock->locksound.Push(sc.String);
if (!sc.GetString())
{
break;
}
if (!sc.Compare(","))
{
sc.UnGet();
break;
}
}
break;
default:
mi = PClass::FindActor(sc.String);
if (mi)
{
keygroup = new Keygroup;
AddOneKey(keygroup, mi, sc);
if (keygroup)
{
keygroup->anykeylist.ShrinkToFit();
lock->keylist.Push(keygroup);
}
}
break;
}
}
// copy the messages if the other one does not exist
if (lock->RemoteMsg.IsEmpty() && lock->Message.IsNotEmpty())
{
lock->RemoteMsg = lock->Message;
}
if (lock->Message.IsEmpty() && lock->RemoteMsg.IsNotEmpty())
{
lock->Message = lock->RemoteMsg;
}
lock->keylist.ShrinkToFit();
}
//===========================================================================
//
// Clears all key numbers so the parser can assign its own ones
// This ensures that only valid keys are considered by the key cheats
//
//===========================================================================
static void ClearLocks()
{
unsigned int i;
for(i = 0; i < PClassActor::AllActorClasses.Size(); i++)
{
if (PClassActor::AllActorClasses[i]->IsDescendantOf(RUNTIME_CLASS(AKey)))
{
AKey *key = static_cast<AKey*>(GetDefaultByType(PClassActor::AllActorClasses[i]));
if (key != NULL)
{
key->KeyNumber = 0;
}
}
}
for(i = 0; i < 256; i++)
{
if (locks[i] != NULL)
{
delete locks[i];
locks[i] = NULL;
}
}
currentnumber = 0;
keysdone = false;
}
//===========================================================================
//
// P_InitKeyMessages
//
//===========================================================================
void P_InitKeyMessages()
{
int lastlump, lump;
lastlump = 0;
ClearLocks();
while ((lump = Wads.FindLump ("LOCKDEFS", &lastlump)) != -1)
{
FScanner sc(lump);
while (sc.GetString ())
{
if (sc.Compare("LOCK"))
{
ParseLock(sc);
}
else if (sc.Compare("CLEARLOCKS"))
{
// clear all existing lock definitions and key numbers
ClearLocks();
}
else
{
sc.ScriptError("Unknown command %s in LockDef", sc.String);
}
}
sc.Close();
}
keysdone = true;
}
//===========================================================================
//
// P_DeinitKeyMessages
//
//===========================================================================
void P_DeinitKeyMessages()
{
ClearLocks();
}
//===========================================================================
//
// P_CheckKeys
//
// Returns true if the actor has the required key. If not, a message is
// shown if the actor is also the consoleplayer's camarea, and false is
// returned.
//
//===========================================================================
bool P_CheckKeys (AActor *owner, int keynum, bool remote)
{
const char *failtext = NULL;
FSoundID *failsound;
int numfailsounds;
if (owner == NULL) return false;
if (keynum<=0 || keynum>255) return true;
// Just a safety precaution. The messages should have been initialized upon game start.
if (!keysdone) P_InitKeyMessages();
FSoundID failage[2] = { "*keytry", "misc/keytry" };
if (!locks[keynum])
{
if (keynum == 103 && (gameinfo.flags & GI_SHAREWARE))
failtext = "$TXT_RETAIL_ONLY";
else
failtext = "$TXT_DOES_NOT_WORK";
failsound = failage;
numfailsounds = countof(failage);
}
else
{
if (locks[keynum]->check(owner)) return true;
failtext = remote? locks[keynum]->RemoteMsg : locks[keynum]->Message;
failsound = &locks[keynum]->locksound[0];
numfailsounds = locks[keynum]->locksound.Size();
}
// If we get here, that means the actor isn't holding an appropriate key.
if (owner == players[consoleplayer].camera)
{
PrintMessage(failtext);
// Play the first defined key sound.
for (int i = 0; i < numfailsounds; ++i)
{
if (failsound[i] != 0)
{
int snd = S_FindSkinnedSound(owner, failsound[i]);
if (snd != 0)
{
S_Sound (owner, CHAN_VOICE, snd, 1, ATTN_NORM);
break;
}
}
}
}
return false;
}
//==========================================================================
//
// AKey implementation
//
//==========================================================================
IMPLEMENT_CLASS(AKey, false, false)
DEFINE_FIELD(AKey, KeyNumber)
bool AKey::HandlePickup (AInventory *item)
{
// In single player, you can pick up an infinite number of keys
// even though you can only hold one of each.
if (multiplayer)
{
return Super::HandlePickup (item);
}
if (GetClass() == item->GetClass())
{
item->ItemFlags |= IF_PICKUPGOOD;
return true;
}
return false;
}
bool AKey::ShouldStay ()
{
return !!multiplayer;
}
//==========================================================================
//
// These functions can be used to get color information for
// automap display of keys and locked doors
//
//==========================================================================
int P_GetMapColorForLock (int lock)
{
if (lock > 0 && lock < 256)
{
if (locks[lock]) return locks[lock]->rgb;
}
return -1;
}
//==========================================================================
//
//
//
//==========================================================================
int P_GetMapColorForKey (AInventory * key)
{
int i;
for (i = 0; i < 256; i++)
{
if (locks[i] && locks[i]->check(key)) return locks[i]->rgb;
}
return 0;
}

View file

@ -1,24 +0,0 @@
#ifndef A_KEYS_H
#define A_KEYS_H
#include "a_pickups.h"
class AKey : public AInventory
{
DECLARE_CLASS (AKey, AInventory)
public:
virtual bool HandlePickup (AInventory *item);
BYTE KeyNumber;
protected:
virtual bool ShouldStay ();
};
bool P_CheckKeys (AActor *owner, int keynum, bool remote);
void P_InitKeyMessages ();
void P_DeinitKeyMessages ();
int P_GetMapColorForLock (int lock);
int P_GetMapColorForKey (AInventory *key);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,606 +0,0 @@
#ifndef __A_PICKUPS_H__
#define __A_PICKUPS_H__
#include "actor.h"
#include "info.h"
#include "s_sound.h"
#define NUM_WEAPON_SLOTS 10
class player_t;
class FConfigFile;
class AWeapon;
class PClassWeapon;
class PClassPlayerPawn;
struct visstyle_t;
class FWeaponSlot
{
public:
FWeaponSlot() { Clear(); }
FWeaponSlot(const FWeaponSlot &other) { Weapons = other.Weapons; }
FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; }
void Clear() { Weapons.Clear(); }
bool AddWeapon (const char *type);
bool AddWeapon (PClassWeapon *type);
void AddWeaponList (const char *list, bool clear);
AWeapon *PickWeapon (player_t *player, bool checkammo = false);
int Size () const { return (int)Weapons.Size(); }
int LocateWeapon (PClassWeapon *type);
inline PClassWeapon *GetWeapon (int index) const
{
if ((unsigned)index < Weapons.Size())
{
return Weapons[index].Type;
}
else
{
return NULL;
}
}
friend struct FWeaponSlots;
private:
struct WeaponInfo
{
PClassWeapon *Type;
int Position;
};
void SetInitialPositions();
void Sort();
TArray<WeaponInfo> Weapons;
};
// FWeaponSlots::AddDefaultWeapon return codes
enum ESlotDef
{
SLOTDEF_Exists, // Weapon was already assigned a slot
SLOTDEF_Added, // Weapon was successfully added
SLOTDEF_Full // The specifed slot was full
};
struct FWeaponSlots
{
FWeaponSlots() { Clear(); }
FWeaponSlots(const FWeaponSlots &other);
FWeaponSlot Slots[NUM_WEAPON_SLOTS];
AWeapon *PickNextWeapon (player_t *player);
AWeapon *PickPrevWeapon (player_t *player);
void Clear ();
bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index);
ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type);
void AddExtraWeapons();
void SetFromGameInfo();
void SetFromPlayer(PClassPlayerPawn *type);
void StandardSetup(PClassPlayerPawn *type);
void LocalSetup(PClassActor *type);
void SendDifferences(int playernum, const FWeaponSlots &other);
int RestoreSlots (FConfigFile *config, const char *section);
void PrintSettings();
void AddSlot(int slot, PClassWeapon *type, bool feedback);
void AddSlotDefault(int slot, PClassWeapon *type, bool feedback);
};
void P_PlaybackKeyConfWeapons(FWeaponSlots *slots);
void Net_WriteWeapon(PClassWeapon *type);
PClassWeapon *Net_ReadWeapon(BYTE **stream);
void P_SetupWeapons_ntohton();
void P_WriteDemoWeaponsChunk(BYTE **demo);
void P_ReadDemoWeaponsChunk(BYTE **demo);
/************************************************************************/
/* Class definitions */
/************************************************************************/
// A pickup is anything the player can pickup (i.e. weapons, ammo, powerups, etc)
enum
{
IF_ACTIVATABLE = 1<<0, // can be activated
IF_ACTIVATED = 1<<1, // is currently activated
IF_PICKUPGOOD = 1<<2, // HandlePickup wants normal pickup FX to happen
IF_QUIET = 1<<3, // Don't give feedback when picking up
IF_AUTOACTIVATE = 1<<4, // Automatically activate item on pickup
IF_UNDROPPABLE = 1<<5, // Item cannot be removed unless done explicitly with RemoveInventory
IF_INVBAR = 1<<6, // Item appears in the inventory bar
IF_HUBPOWER = 1<<7, // Powerup is kept when moving in a hub
IF_UNTOSSABLE = 1<<8, // The player cannot manually drop the item
IF_ADDITIVETIME = 1<<9, // when picked up while another item is active, time is added instead of replaced.
IF_ALWAYSPICKUP = 1<<10, // For IF_AUTOACTIVATE, MaxAmount=0 items: Always "pick up", even if it doesn't do anything
IF_FANCYPICKUPSOUND = 1<<11, // Play pickup sound in "surround" mode
IF_BIGPOWERUP = 1<<12, // Affected by RESPAWN_SUPER dmflag
IF_KEEPDEPLETED = 1<<13, // Items with this flag are retained even when they run out.
IF_IGNORESKILL = 1<<14, // Ignores any skill related multiplicators when giving this item.
IF_CREATECOPYMOVED = 1<<15, // CreateCopy changed the owner (copy's Owner field holds new owner).
IF_INITEFFECTFAILED = 1<<16, // CreateCopy tried to activate a powerup and activation failed (can happen with PowerMorph)
IF_NOATTENPICKUPSOUND = 1<<17, // Play pickup sound with ATTN_NONE
IF_PERSISTENTPOWER = 1<<18, // Powerup is kept when travelling between levels
IF_RESTRICTABSOLUTELY = 1<<19, // RestrictedTo and ForbiddenTo do not allow pickup in any form by other classes
IF_NEVERRESPAWN = 1<<20, // Never, ever respawns
IF_NOSCREENFLASH = 1<<21, // No pickup flash on the player's screen
IF_TOSSED = 1<<22, // Was spawned by P_DropItem (i.e. as a monster drop)
IF_ALWAYSRESPAWN = 1<<23, // Always respawn, regardless of dmflag
IF_TRANSFER = 1<<24, // All inventory items that the inventory item contains is also transfered to the pickuper
IF_NOTELEPORTFREEZE = 1<<25, // does not 'freeze' the player right after teleporting.
};
class PClassInventory : public PClassActor
{
DECLARE_CLASS(PClassInventory, PClassActor)
public:
PClassInventory();
virtual void DeriveData(PClass *newclass);
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
void Finalize(FStateDefinitions &statedef);
FString PickupMessage;
int GiveQuest; // Optionally give one of the quest items.
FTextureID AltHUDIcon;
TArray<PClassPlayerPawn *> RestrictedToPlayerClass;
TArray<PClassPlayerPawn *> ForbiddenToPlayerClass;
};
class AInventory : public AActor
{
DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory)
HAS_OBJECT_POINTERS
public:
virtual void Touch (AActor *toucher);
virtual void Serialize(FSerializer &arc);
virtual void MarkPrecacheSounds() const;
virtual void BeginPlay ();
virtual void Destroy () override;
virtual void DepleteOrDestroy ();
virtual void Tick ();
virtual bool ShouldRespawn ();
virtual bool ShouldStay ();
virtual void Hide ();
bool CallTryPickup (AActor *toucher, AActor **toucher_return = NULL);
virtual void DoPickupSpecial (AActor *toucher);
virtual bool SpecialDropAction (AActor *dropper);
bool CallSpecialDropAction(AActor *dropper);
virtual bool DrawPowerup (int x, int y);
virtual void DoEffect ();
virtual bool Grind(bool items);
virtual FString PickupMessage ();
FString GetPickupMessage();
virtual void PlayPickupSound (AActor *toucher);
bool DoRespawn ();
AInventory *PrevItem(); // Returns the item preceding this one in the list.
AInventory *PrevInv(); // Returns the previous item with IF_INVBAR set.
AInventory *NextInv(); // Returns the next item with IF_INVBAR set.
TObjPtr<AActor> Owner; // Who owns this item? NULL if it's still a pickup.
int Amount; // Amount of item this instance has
int MaxAmount; // Max amount of item this instance can have
int InterHubAmount; // Amount of item that can be kept between hubs or levels
int RespawnTics; // Tics from pickup time to respawn time
FTextureID Icon; // Icon to show on status bar or HUD
int DropTime; // Countdown after dropping
PClassActor *SpawnPointClass; // For respawning like Heretic's mace
DWORD ItemFlags;
PClassActor *PickupFlash; // actor to spawn as pickup flash
FSoundIDNoInit PickupSound;
void BecomeItem ();
void BecomePickup ();
virtual void AttachToOwner (AActor *other);
virtual void DetachFromOwner ();
virtual AInventory *CreateCopy (AActor *other);
AInventory *CallCreateCopy(AActor *other);
virtual AInventory *CreateTossable ();
AInventory *CallCreateTossable();
virtual bool GoAway ();
virtual void GoAwayAndDie ();
virtual bool HandlePickup (AInventory *item);
bool CallHandlePickup(AInventory *item);
virtual bool Use (bool pickup);
bool CallUse(bool pickup);
virtual void Travelled ();
virtual void OwnerDied ();
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage);
virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive);
virtual double GetSpeedFactor();
virtual bool GetNoTeleportFreeze();
virtual int AlterWeaponSprite (visstyle_t *vis);
virtual PalEntry GetBlend ();
PalEntry CallGetBlend();
virtual bool TryPickup (AActor *&toucher);
virtual bool TryPickupRestricted (AActor *&toucher);
protected:
bool CanPickup(AActor * toucher);
void GiveQuest(AActor * toucher);
private:
static int StaticLastMessageTic;
static FString StaticLastMessage;
};
class AStateProvider : public AInventory
{
DECLARE_CLASS(AStateProvider, AInventory)
};
// CustomInventory: Supports the Use, Pickup, and Drop states from 96x
class ACustomInventory : public AStateProvider
{
DECLARE_CLASS (ACustomInventory, AStateProvider)
public:
// This is used when an inventory item's use state sequence is executed.
bool CallStateChain (AActor *actor, FState *state);
bool TryPickup (AActor *&toucher);
bool Use (bool pickup);
bool SpecialDropAction (AActor *dropper);
};
// Ammo: Something a weapon needs to operate
class PClassAmmo : public PClassInventory
{
DECLARE_CLASS(PClassAmmo, PClassInventory)
protected:
virtual void DeriveData(PClass *newclass);
public:
PClassAmmo();
int DropAmount; // Specifies the amount for a dropped ammo item.
};
class AAmmo : public AInventory
{
DECLARE_CLASS_WITH_META(AAmmo, AInventory, PClassAmmo)
public:
void Serialize(FSerializer &arc);
AInventory *CreateCopy (AActor *other);
bool HandlePickup (AInventory *item);
PClassActor *GetParentAmmo () const;
AInventory *CreateTossable ();
int BackpackAmount, BackpackMaxAmount;
};
// A weapon is just that.
class PClassWeapon : public PClassInventory
{
DECLARE_CLASS(PClassWeapon, PClassInventory);
protected:
virtual void DeriveData(PClass *newclass);
public:
PClassWeapon();
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
void Finalize(FStateDefinitions &statedef);
int SlotNumber;
int SlotPriority;
};
class AWeapon : public AStateProvider
{
DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon)
HAS_OBJECT_POINTERS
public:
DWORD WeaponFlags;
PClassAmmo *AmmoType1, *AmmoType2; // Types of ammo used by this weapon
int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon
int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon
int AmmoUse1, AmmoUse2; // How much ammo to use with each shot
int Kickback;
float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double)
FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle
PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one
PClassActor *ProjectileType; // Projectile used by primary attack
PClassActor *AltProjectileType; // Projectile used by alternate attack
int SelectionOrder; // Lower-numbered weapons get picked first
int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo
double MoveCombatDist; // Used by bots, but do they *really* need it?
int ReloadCounter; // For A_CheckForReload
int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double)
float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs.
float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction.
// In-inventory instance variables
TObjPtr<AAmmo> Ammo1, Ammo2;
TObjPtr<AWeapon> SisterWeapon;
float FOVScale;
int Crosshair; // 0 to use player's crosshair
bool GivenAsMorphWeapon;
bool bAltFire; // Set when this weapon's alternate fire is used.
virtual void MarkPrecacheSounds() const;
virtual void Serialize(FSerializer &arc);
virtual bool ShouldStay ();
virtual void AttachToOwner (AActor *other);
virtual bool HandlePickup (AInventory *item);
virtual AInventory *CreateCopy (AActor *other);
virtual AInventory *CreateTossable ();
virtual bool TryPickup (AActor *&toucher);
virtual bool TryPickupRestricted (AActor *&toucher);
virtual bool PickupForAmmo (AWeapon *ownedWeapon);
virtual bool Use (bool pickup);
virtual void Destroy() override;
FState *GetUpState ();
FState *GetDownState ();
FState *GetReadyState ();
FState *GetAtkState (bool hold);
FState *GetAltAtkState (bool hold);
FState *GetStateForButtonName (FName button);
virtual void PostMorphWeapon ();
virtual void EndPowerup ();
void CallEndPowerup();
enum
{
PrimaryFire,
AltFire,
EitherFire
};
bool CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo=false, int ammocount = -1);
bool DepleteAmmo (bool altFire, bool checkEnough=true, int ammouse = -1);
enum
{
BobNormal,
BobInverse,
BobAlpha,
BobInverseAlpha,
BobSmooth,
BobInverseSmooth
};
protected:
AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount);
bool AddExistingAmmo (AAmmo *ammo, int amount);
AWeapon *AddWeapon (PClassWeapon *weapon);
};
enum
{
WIF_NOAUTOFIRE = 0x00000001, // weapon does not autofire
WIF_READYSNDHALF = 0x00000002, // ready sound is played ~1/2 the time
WIF_DONTBOB = 0x00000004, // don't bob the weapon
WIF_AXEBLOOD = 0x00000008, // weapon makes axe blood on impact (Hexen only)
WIF_NOALERT = 0x00000010, // weapon does not alert monsters
WIF_AMMO_OPTIONAL = 0x00000020, // weapon can use ammo but does not require it
WIF_ALT_AMMO_OPTIONAL = 0x00000040, // alternate fire can use ammo but does not require it
WIF_PRIMARY_USES_BOTH = 0x00000080, // primary fire uses both ammo
WIF_ALT_USES_BOTH = 0x00000100, // alternate fire uses both ammo
WIF_WIMPY_WEAPON = 0x00000200, // change away when ammo for another weapon is replenished
WIF_POWERED_UP = 0x00000400, // this is a tome-of-power'ed version of its sister
WIF_AMMO_CHECKBOTH = 0x00000800, // check for both primary and secondary fire before switching it off
WIF_NO_AUTO_SWITCH = 0x00001000, // never switch to this weapon when it's picked up
WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback
WIF_NOAUTOAIM = 0x00004000, // this weapon never uses autoaim (useful for ballistic projectiles)
WIF_MELEEWEAPON = 0x00008000, // melee weapon. Used by bots and monster AI.
WIF_DEHAMMO = 0x00010000, // Uses Doom's original amount of ammo for the respective attack functions so that old DEHACKED patches work as intended.
// AmmoUse1 will be set to the first attack's ammo use so that checking for empty weapons still works
WIF_NODEATHDESELECT = 0x00020000, // Don't jump to the Deselect state when the player dies
WIF_NODEATHINPUT = 0x00040000, // The weapon cannot be fired/reloaded/whatever when the player is dead
WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil)
// Flags used only by bot AI:
WIF_BOT_REACTION_SKILL_THING = 1<<31, // I don't understand this
WIF_BOT_EXPLOSIVE = 1<<30, // weapon fires an explosive
WIF_BOT_BFG = 1<<28, // this is a BFG
};
class AWeaponGiver : public AWeapon
{
DECLARE_CLASS(AWeaponGiver, AWeapon)
public:
bool TryPickup(AActor *&toucher);
void Serialize(FSerializer &arc);
double DropAmmoFactor;
};
// Health is some item that gives the player health when picked up.
class PClassHealth : public PClassInventory
{
DECLARE_CLASS(PClassHealth, PClassInventory)
protected:
public:
PClassHealth();
virtual void DeriveData(PClass *newclass);
FString LowHealthMessage;
int LowHealth;
};
class AHealth : public AInventory
{
DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth)
public:
int PrevHealth;
virtual bool TryPickup (AActor *&other);
virtual FString PickupMessage ();
};
// HealthPickup is some item that gives the player health when used.
class AHealthPickup : public AInventory
{
DECLARE_CLASS (AHealthPickup, AInventory)
public:
int autousemode;
virtual void Serialize(FSerializer &arc);
virtual AInventory *CreateCopy (AActor *other);
virtual AInventory *CreateTossable ();
virtual bool HandlePickup (AInventory *item);
virtual bool Use (bool pickup);
};
// 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);
virtual void Tick ();
virtual AInventory *CreateCopy (AActor *other);
virtual bool HandlePickup (AInventory *item);
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage);
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);
virtual AInventory *CreateCopy (AActor *other);
virtual bool Use (bool pickup);
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);
virtual AInventory *CreateCopy (AActor *other);
virtual bool Use (bool pickup);
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);
virtual AInventory *CreateCopy (AActor *other);
virtual AInventory *CreateTossable ();
virtual bool HandlePickup (AInventory *item);
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage);
void DepleteOrDestroy();
double Slots[5];
double SlotsIncrement[4];
protected:
bool AddArmorToSlot (AActor *actor, int slot, int amount);
};
// PuzzleItems work in conjunction with the UsePuzzleItem special
class PClassPuzzleItem : public PClassInventory
{
DECLARE_CLASS(PClassPuzzleItem, PClassInventory);
protected:
public:
virtual void DeriveData(PClass *newclass);
FString PuzzFailMessage;
};
class APuzzleItem : public AInventory
{
DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem)
public:
bool ShouldStay ();
bool Use (bool pickup);
bool HandlePickup (AInventory *item);
int PuzzleItemNumber;
};
// A MapRevealer reveals the whole map for the player who picks it up.
class AMapRevealer : public AInventory
{
DECLARE_CLASS (AMapRevealer, AInventory)
public:
bool TryPickup (AActor *&toucher);
};
// A backpack gives you one clip of each ammo and doubles your
// normal maximum ammo amounts.
class ABackpackItem : public AInventory
{
DECLARE_CLASS (ABackpackItem, AInventory)
public:
void Serialize(FSerializer &arc);
bool HandlePickup (AInventory *item);
AInventory *CreateCopy (AActor *other);
AInventory *CreateTossable ();
void DetachFromOwner ();
bool bDepleted;
};
// A score item is picked up without being added to the inventory.
// It differs from FakeInventory by doing nothing more than increasing the player's score.
class AScoreItem : public AInventory
{
DECLARE_CLASS (AScoreItem, AInventory)
public:
bool TryPickup(AActor *&toucher);
};
extern PClassActor *QuestItemClasses[31];
#endif //__A_PICKUPS_H__

View file

@ -1,56 +0,0 @@
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "s_sound.h"
#include "c_console.h"
#include "doomstat.h"
#include "v_font.h"
IMPLEMENT_CLASS(PClassPuzzleItem, false, false)
void PClassPuzzleItem::DeriveData(PClass *newclass)
{
Super::DeriveData(newclass);
assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem)));
static_cast<PClassPuzzleItem *>(newclass)->PuzzFailMessage = PuzzFailMessage;
}
IMPLEMENT_CLASS(APuzzleItem, false, false)
DEFINE_FIELD(APuzzleItem, PuzzleItemNumber)
bool APuzzleItem::HandlePickup (AInventory *item)
{
// Can't carry more than 1 of each puzzle item in coop netplay
if (multiplayer && !deathmatch && item->GetClass() == GetClass())
{
return true;
}
return Super::HandlePickup (item);
}
bool APuzzleItem::Use (bool pickup)
{
if (P_UsePuzzleItem (Owner, PuzzleItemNumber))
{
return true;
}
// [RH] Always play the sound if the use fails.
S_Sound (Owner, CHAN_VOICE, "*puzzfail", 1, ATTN_IDLE);
if (Owner != NULL && Owner->CheckLocalView (consoleplayer))
{
FString message = GetClass()->PuzzFailMessage;
if (message.IsNotEmpty() && message[0] == '$') message = GStrings[&message[1]];
if (message.IsEmpty()) message = GStrings("TXT_USEPUZZLEFAILED");
C_MidPrintBold (SmallFont, message);
}
return false;
}
bool APuzzleItem::ShouldStay ()
{
return !!multiplayer;
}

View file

@ -1,211 +0,0 @@
#include "a_pickups.h"
#include "a_weaponpiece.h"
#include "doomstat.h"
#include "serializer.h"
IMPLEMENT_CLASS(PClassWeaponPiece, false, false)
IMPLEMENT_CLASS(AWeaponHolder, false, false)
DEFINE_FIELD(AWeaponHolder, PieceMask);
DEFINE_FIELD(AWeaponHolder, PieceWeapon);
void PClassWeaponPiece::ReplaceClassRef(PClass *oldclass, PClass *newclass)
{
Super::ReplaceClassRef(oldclass, newclass);
AWeaponPiece *def = (AWeaponPiece*)Defaults;
if (def != NULL)
{
if (def->WeaponClass == oldclass) def->WeaponClass = static_cast<PClassWeapon *>(newclass);
}
}
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_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 (ShouldStay())
{ // Can't pick up weapons for other classes in coop netplay
return false;
}
AWeapon * Defaults=(AWeapon*)GetDefaultByType(WeaponClass);
bool gaveSome = !!(toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1) +
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2));
if (gaveSome)
{
GoAwayAndDie ();
}
return gaveSome;
}
//==========================================================================
//
// TryPickupWeaponPiece
//
//==========================================================================
bool AWeaponPiece::TryPickup (AActor *&toucher)
{
AInventory * inv;
AWeaponHolder * hold=NULL;
bool shouldStay = PrivateShouldStay ();
int gaveAmmo;
AWeapon * Defaults=(AWeapon*)GetDefaultByType(WeaponClass);
FullWeapon=NULL;
for(inv=toucher->Inventory;inv;inv=inv->Inventory)
{
if (inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder)))
{
hold=static_cast<AWeaponHolder*>(inv);
if (hold->PieceWeapon==WeaponClass) break;
hold=NULL;
}
}
if (!hold)
{
hold=static_cast<AWeaponHolder*>(Spawn(RUNTIME_CLASS(AWeaponHolder)));
hold->BecomeItem();
hold->AttachToOwner(toucher);
hold->PieceMask=0;
hold->PieceWeapon=WeaponClass;
}
if (shouldStay)
{
// Cooperative net-game
if (hold->PieceMask & PieceValue)
{
// Already has the piece
return false;
}
toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1);
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2);
}
else
{ // Deathmatch or singleplayer game
gaveAmmo = toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1) +
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2);
if (hold->PieceMask & PieceValue)
{
// Already has the piece, check if mana needed
if (!gaveAmmo) return false;
GoAwayAndDie();
return true;
}
}
hold->PieceMask |= PieceValue;
// Check if weapon assembled
if (hold->PieceMask== (1<<Defaults->health)-1)
{
if (!toucher->FindInventory (WeaponClass))
{
FullWeapon= static_cast<AWeapon*>(Spawn(WeaponClass));
// The weapon itself should not give more ammo to the player!
FullWeapon->AmmoGive1=0;
FullWeapon->AmmoGive2=0;
FullWeapon->AttachToOwner(toucher);
FullWeapon->AmmoGive1=Defaults->AmmoGive1;
FullWeapon->AmmoGive2=Defaults->AmmoGive2;
}
}
GoAwayAndDie();
return true;
}
bool AWeaponPiece::ShouldStay ()
{
return PrivateShouldStay ();
}
bool AWeaponPiece::PrivateShouldStay ()
{
// We want a weapon piece to behave like a weapon, so follow the exact
// same logic as weapons when deciding whether or not to stay.
if (((multiplayer &&
(!deathmatch && !alwaysapplydmflags)) || (dmflags & DF_WEAPONS_STAY)) &&
!(flags&MF_DROPPED))
{
return true;
}
return false;
}
//===========================================================================
//
// PickupMessage
//
// Returns the message to print when this actor is picked up.
//
//===========================================================================
FString AWeaponPiece::PickupMessage ()
{
if (FullWeapon)
{
return FullWeapon->PickupMessage();
}
else
{
return Super::PickupMessage();
}
}
//===========================================================================
//
// DoPlayPickupSound
//
// Plays a sound when this actor is picked up.
//
//===========================================================================
void AWeaponPiece::PlayPickupSound (AActor *toucher)
{
if (FullWeapon)
{
FullWeapon->PlayPickupSound(toucher);
}
else
{
Super::PlayPickupSound(toucher);
}
}

View file

@ -1,45 +0,0 @@
#pragma once
#include "a_pickups.h"
//
class PClassWeaponPiece : public PClassInventory
{
DECLARE_CLASS(PClassWeaponPiece, PClassInventory)
protected:
public:
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
};
class AWeaponPiece : public AInventory
{
DECLARE_CLASS_WITH_META(AWeaponPiece, AInventory, PClassWeaponPiece)
HAS_OBJECT_POINTERS
protected:
bool PrivateShouldStay ();
public:
void Serialize(FSerializer &arc);
bool TryPickup (AActor *&toucher);
bool TryPickupRestricted (AActor *&toucher);
bool ShouldStay ();
virtual FString PickupMessage ();
virtual void PlayPickupSound (AActor *toucher);
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;
void Serialize(FSerializer &arc);
};

File diff suppressed because it is too large Load diff