- scriptified BasicArmor and fixed a few errors in the conversion.

This commit is contained in:
Christoph Oelckers 2017-01-18 22:15:48 +01:00
commit 3148496f57
9 changed files with 298 additions and 336 deletions

View file

@ -1948,19 +1948,18 @@ static int PatchMisc (int dummy)
// Update default item properties by patching the affected items
// Note: This won't have any effect on DECORATE derivates of these items!
ABasicArmorPickup *armor;
armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("GreenArmor"));
auto armor = GetDefaultByName ("GreenArmor");
if (armor!=NULL)
{
armor->SaveAmount = 100 * deh.GreenAC;
armor->SavePercent = deh.GreenAC == 1 ? 0.33335 : 0.5;
armor->IntVar(NAME_SaveAmount) = 100 * deh.GreenAC;
armor->FloatVar(NAME_SavePercent) = deh.GreenAC == 1 ? 0.33335 : 0.5;
}
armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("BlueArmor"));
armor = GetDefaultByName ("BlueArmor");
if (armor!=NULL)
{
armor->SaveAmount = 100 * deh.BlueAC;
armor->SavePercent = deh.BlueAC == 1 ? 0.33335 : 0.5;
armor->IntVar(NAME_SaveAmount) = 100 * deh.BlueAC;
armor->FloatVar(NAME_SavePercent) = deh.BlueAC == 1 ? 0.33335 : 0.5;
}
auto barmor = GetDefaultByName ("ArmorBonus");

View file

@ -47,7 +47,6 @@
IMPLEMENT_CLASS(AArmor, false, false)
IMPLEMENT_CLASS(ABasicArmor, false, false)
IMPLEMENT_CLASS(ABasicArmorPickup, false, false)
IMPLEMENT_CLASS(AHexenArmor, false, false)
//===========================================================================
@ -85,231 +84,6 @@ void ABasicArmor::Serialize(FSerializer &arc)
("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 :: 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 (PClass::FindActor(NAME_BasicArmorPickup)))
{
ABasicArmorPickup *inInv = static_cast<ABasicArmorPickup*>(probe);
if (best == NULL || best->SavePercent < inInv->SavePercent)
{
best = inInv;
}
}
probe = probe->Inventory;
}
if (best != NULL)
{
Owner->UseInventory (best);
}
}
damage = newdamage;
}
// Once the armor has absorbed its part of the damage, then apply its damage factor, if any, to the player
if ((damage > 0) && (ArmorType != NAME_None)) // BasicArmor is not going to have any damage factor, so skip it.
{
// This code is taken and adapted from APowerProtection::ModifyDamage().
// The differences include not using a default value, and of course the way
// the damage factor info is obtained.
// ApplyDamageFactors(ArmorType, damageType, damage, damage);
DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors;
if (df != NULL)
{
damage = newdamage = df->Apply(damageType, damage);
}
}
}
//===========================================================================
//
//
// BasicArmorPickup
//
//
//===========================================================================
DEFINE_FIELD(ABasicArmorPickup, SavePercent)
DEFINE_FIELD(ABasicArmorPickup, MaxAbsorb)
DEFINE_FIELD(ABasicArmorPickup, MaxFullAbsorb)
DEFINE_FIELD(ABasicArmorPickup, SaveAmount)
//===========================================================================
//
// ABasicArmorPickup :: Serialize
//
//===========================================================================
void ABasicArmorPickup::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
auto def = (ABasicArmorPickup *)GetDefault();
arc("savepercent", SavePercent, def->SavePercent)
("saveamount", SaveAmount, def->SaveAmount)
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb);
}
//===========================================================================
//
// ABasicArmorPickup :: CreateCopy
//
//===========================================================================
AInventory *ABasicArmorPickup::CreateCopy (AActor *other)
{
ABasicArmorPickup *copy = static_cast<ABasicArmorPickup *> (Super::CreateCopy (other));
if (!(ItemFlags & IF_IGNORESKILL))
{
SaveAmount = int(SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
}
copy->SavePercent = SavePercent;
copy->SaveAmount = SaveAmount;
copy->MaxAbsorb = MaxAbsorb;
copy->MaxFullAbsorb = MaxFullAbsorb;
return copy;
}
//===========================================================================
//
// ABasicArmorPickup :: Use
//
// Either gives you new armor or replaces the armor you already have (if
// the SaveAmount is greater than the amount of armor you own). When the
// item is auto-activated, it will only be activated if its max amount is 0
// or if you have no armor active already.
//
//===========================================================================
bool ABasicArmorPickup::Use (bool pickup)
{
ABasicArmor *armor = Owner->FindInventory<ABasicArmor> ();
if (armor == NULL)
{
armor = Spawn<ABasicArmor> ();
armor->BecomeItem ();
Owner->AddInventory (armor);
}
else
{
// If you already have more armor than this item gives you, you can't
// use it.
if (armor->Amount >= SaveAmount + armor->BonusCount)
{
return false;
}
// Don't use it if you're picking it up and already have some.
if (pickup && armor->Amount > 0 && MaxAmount > 0)
{
return false;
}
}
armor->SavePercent = SavePercent;
armor->Amount = SaveAmount + armor->BonusCount;
armor->MaxAmount = SaveAmount;
armor->Icon = Icon;
armor->MaxAbsorb = MaxAbsorb;
armor->MaxFullAbsorb = MaxFullAbsorb;
armor->ArmorType = this->GetClass()->TypeName;
armor->ActualSaveAmount = SaveAmount;
return true;
}
//===========================================================================
//
//

View file

@ -17,9 +17,6 @@ class ABasicArmor : public AArmor
public:
virtual void Serialize(FSerializer &arc) override;
virtual void Tick () override;
virtual AInventory *CreateCopy (AActor *other) override;
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
int AbsorbCount;
double SavePercent;
@ -30,22 +27,6 @@ public:
int ActualSaveAmount;
};
// BasicArmorPickup replaces the armor you have.
class ABasicArmorPickup : public AArmor
{
DECLARE_CLASS (ABasicArmorPickup, AArmor)
public:
virtual void Serialize(FSerializer &arc) override;
virtual AInventory *CreateCopy (AActor *other) override;
virtual bool Use (bool pickup) override;
double SavePercent;
int MaxAbsorb;
int MaxFullAbsorb;
int SaveAmount;
};
// 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

View file

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

View file

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

View file

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

View file

@ -1723,79 +1723,6 @@ DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory)
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(saveamount, I, Armor)
{
PROP_INT_PARM(i, 0);
// Special case here because this property has to work for 2 unrelated classes
if (info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorPickup)) || info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus)))
{
defaults->IntVar(NAME_SaveAmount)=i;
}
else
{
I_Error("\"Armor.SaveAmount\" requires an actor of type \"Armor\"");
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(savepercent, F, Armor)
{
PROP_DOUBLE_PARM(i, 0);
i = clamp(i, 0., 100.)/100.;
// Special case here because this property has to work for 2 unrelated classes
if (info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorPickup)) || info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus)))
{
defaults->FloatVar(NAME_SavePercent) = i;
}
else
{
I_Error("\"Armor.SavePercent\" requires an actor of type \"Armor\"\n");
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(maxabsorb, I, Armor)
{
PROP_INT_PARM(i, 0);
// Special case here because this property has to work for 2 unrelated classes
if (info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorPickup)) || info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus)))
{
defaults->IntVar(NAME_MaxAbsorb) = i;
}
else
{
I_Error("\"Armor.MaxAbsorb\" requires an actor of type \"Armor\"\n");
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(maxfullabsorb, I, Armor)
{
PROP_INT_PARM(i, 0);
// Special case here because this property has to work for 2 unrelated classes
if (info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorPickup)) || info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus)))
{
defaults->IntVar(NAME_MaxFullAbsorb) = i;
}
else
{
I_Error("\"Armor.MaxFullAbsorb\" requires an actor of type \"Armor\"\n");
}
}
//==========================================================================
//
//==========================================================================