- 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:
parent
b1910effd6
commit
014e04ce82
13 changed files with 11 additions and 9 deletions
|
|
@ -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
|
|
@ -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__
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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__
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue