mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-14 00:21:34 +00:00
- scriptified BasicArmor and fixed a few errors in the conversion.
This commit is contained in:
parent
2dd6fb9595
commit
3148496f57
9 changed files with 298 additions and 336 deletions
|
@ -1948,19 +1948,18 @@ static int PatchMisc (int dummy)
|
||||||
|
|
||||||
// Update default item properties by patching the affected items
|
// Update default item properties by patching the affected items
|
||||||
// Note: This won't have any effect on DECORATE derivates of these 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)
|
if (armor!=NULL)
|
||||||
{
|
{
|
||||||
armor->SaveAmount = 100 * deh.GreenAC;
|
armor->IntVar(NAME_SaveAmount) = 100 * deh.GreenAC;
|
||||||
armor->SavePercent = deh.GreenAC == 1 ? 0.33335 : 0.5;
|
armor->FloatVar(NAME_SavePercent) = deh.GreenAC == 1 ? 0.33335 : 0.5;
|
||||||
}
|
}
|
||||||
armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("BlueArmor"));
|
armor = GetDefaultByName ("BlueArmor");
|
||||||
if (armor!=NULL)
|
if (armor!=NULL)
|
||||||
{
|
{
|
||||||
armor->SaveAmount = 100 * deh.BlueAC;
|
armor->IntVar(NAME_SaveAmount) = 100 * deh.BlueAC;
|
||||||
armor->SavePercent = deh.BlueAC == 1 ? 0.33335 : 0.5;
|
armor->FloatVar(NAME_SavePercent) = deh.BlueAC == 1 ? 0.33335 : 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto barmor = GetDefaultByName ("ArmorBonus");
|
auto barmor = GetDefaultByName ("ArmorBonus");
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
|
|
||||||
IMPLEMENT_CLASS(AArmor, false, false)
|
IMPLEMENT_CLASS(AArmor, false, false)
|
||||||
IMPLEMENT_CLASS(ABasicArmor, false, false)
|
IMPLEMENT_CLASS(ABasicArmor, false, false)
|
||||||
IMPLEMENT_CLASS(ABasicArmorPickup, false, false)
|
|
||||||
IMPLEMENT_CLASS(AHexenArmor, false, false)
|
IMPLEMENT_CLASS(AHexenArmor, false, false)
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -85,231 +84,6 @@ void ABasicArmor::Serialize(FSerializer &arc)
|
||||||
("actualsaveamount", ActualSaveAmount, def->ActualSaveAmount);
|
("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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
|
@ -17,9 +17,6 @@ class ABasicArmor : public AArmor
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void Serialize(FSerializer &arc) override;
|
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;
|
int AbsorbCount;
|
||||||
double SavePercent;
|
double SavePercent;
|
||||||
|
@ -30,22 +27,6 @@ public:
|
||||||
int ActualSaveAmount;
|
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
|
// Hexen armor consists of four separate armor types plus a conceptual armor
|
||||||
// type (the player himself) that work together as a single armor.
|
// type (the player himself) that work together as a single armor.
|
||||||
class AHexenArmor : public AArmor
|
class AHexenArmor : public AArmor
|
||||||
|
|
|
@ -47,6 +47,8 @@ gameinfo_t gameinfo;
|
||||||
|
|
||||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype)
|
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype)
|
||||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent)
|
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] =
|
const char *GameNames[17] =
|
||||||
|
|
|
@ -758,6 +758,14 @@ bool DamageTypeDefinition::IgnoreArmor(FName type)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_DamageTypeDefinition, IgnoreArmor)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_NAME(type);
|
||||||
|
ACTION_RETURN_BOOL(DamageTypeDefinition::IgnoreArmor(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// DamageTypeDefinition :: ApplyMobjDamageFactor
|
// DamageTypeDefinition :: ApplyMobjDamageFactor
|
||||||
|
|
|
@ -226,10 +226,12 @@ public:
|
||||||
NoArmor = false;
|
NoArmor = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DamageTypeDefinition *Get(FName type);
|
|
||||||
static bool IgnoreArmor(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);
|
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;
|
class DDropItem;
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -42,11 +42,18 @@ struct Console native
|
||||||
native static void HideConsole();
|
native static void HideConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DamageTypeDefinition native
|
||||||
|
{
|
||||||
|
native static bool IgnoreArmor(Name type);
|
||||||
|
}
|
||||||
|
|
||||||
struct GameInfoStruct native
|
struct GameInfoStruct native
|
||||||
{
|
{
|
||||||
// will be extended as needed.
|
// will be extended as needed.
|
||||||
native Name backpacktype;
|
native Name backpacktype;
|
||||||
native double Armor2Percent;
|
native double Armor2Percent;
|
||||||
|
native String ArmorIcon1;
|
||||||
|
native String ArmorIcon2;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Object native
|
class Object native
|
||||||
|
|
|
@ -1,3 +1,38 @@
|
||||||
|
/*
|
||||||
|
** armor.txt
|
||||||
|
** Implements all variations of armor objects
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 2002-2016 Randy Heit
|
||||||
|
** Copyright 2006-2017 Christoph Oelckers
|
||||||
|
** All rights reserved.
|
||||||
|
**
|
||||||
|
** Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions
|
||||||
|
** are met:
|
||||||
|
**
|
||||||
|
** 1. Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in the
|
||||||
|
** documentation and/or other materials provided with the distribution.
|
||||||
|
** 3. The name of the author may not be used to endorse or promote products
|
||||||
|
** derived from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
class Armor : Inventory native
|
class Armor : Inventory native
|
||||||
{
|
{
|
||||||
Default
|
Default
|
||||||
|
@ -6,6 +41,14 @@ class Armor : Inventory native
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// BasicArmor
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
class BasicArmor : Armor native
|
class BasicArmor : Armor native
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -22,6 +65,54 @@ class BasicArmor : Armor native
|
||||||
+Inventory.KEEPDEPLETED
|
+Inventory.KEEPDEPLETED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// ABasicArmor :: Tick
|
||||||
|
//
|
||||||
|
// If BasicArmor is given to the player by means other than a
|
||||||
|
// BasicArmorPickup, then it may not have an icon set. Fix that here.
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override void Tick ()
|
||||||
|
{
|
||||||
|
Super.Tick ();
|
||||||
|
AbsorbCount = 0;
|
||||||
|
if (!Icon.isValid())
|
||||||
|
{
|
||||||
|
String icontex = gameinfo.ArmorIcon1;
|
||||||
|
|
||||||
|
if (SavePercent >= gameinfo.Armor2Percent && gameinfo.ArmorIcon2.Length() != 0)
|
||||||
|
icontex = gameinfo.ArmorIcon2;
|
||||||
|
|
||||||
|
if (icontex.Length() != 0)
|
||||||
|
Icon = TexMan.CheckForTexture (icontex, TexMan.TYPE_Any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// ABasicArmor :: CreateCopy
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override Inventory CreateCopy (Actor other)
|
||||||
|
{
|
||||||
|
// BasicArmor that is in use is stored in the inventory as BasicArmor.
|
||||||
|
// BasicArmor that is in reserve is not.
|
||||||
|
let copy = BasicArmor(Spawn("BasicArmor"));
|
||||||
|
copy.SavePercent = SavePercent != 0 ? SavePercent : 0.33335; // slightly more than 1/3 to avoid roundoff errors.
|
||||||
|
copy.Amount = Amount;
|
||||||
|
copy.MaxAmount = MaxAmount;
|
||||||
|
copy.Icon = Icon;
|
||||||
|
copy.BonusCount = BonusCount;
|
||||||
|
copy.ArmorType = ArmorType;
|
||||||
|
copy.ActualSaveAmount = ActualSaveAmount;
|
||||||
|
GoAwayAndDie ();
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// ABasicArmor :: HandlePickup
|
// ABasicArmor :: HandlePickup
|
||||||
|
@ -50,7 +141,85 @@ class BasicArmor : Armor native
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// ABasicArmor :: AbsorbDamage
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override void AbsorbDamage (int damage, Name damageType, out int newdamage)
|
||||||
|
{
|
||||||
|
int saved;
|
||||||
|
|
||||||
|
if (!DamageTypeDefinition.IgnoreArmor(damageType))
|
||||||
|
{
|
||||||
|
int full = MAX(0, MaxFullAbsorb - AbsorbCount);
|
||||||
|
|
||||||
|
if (damage < full)
|
||||||
|
{
|
||||||
|
saved = damage;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
saved = full + int((damage - full) * SavePercent);
|
||||||
|
if (MaxAbsorb > 0 && saved + AbsorbCount > MaxAbsorb)
|
||||||
|
{
|
||||||
|
saved = MAX(0, MaxAbsorb - AbsorbCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Amount < saved)
|
||||||
|
{
|
||||||
|
saved = Amount;
|
||||||
|
}
|
||||||
|
newdamage -= saved;
|
||||||
|
Amount -= saved;
|
||||||
|
AbsorbCount += saved;
|
||||||
|
if (Amount == 0)
|
||||||
|
{
|
||||||
|
// The armor has become useless
|
||||||
|
SavePercent = 0;
|
||||||
|
ArmorType = 'None'; // Not NAME_BasicArmor.
|
||||||
|
// Now see if the player has some more armor in their inventory
|
||||||
|
// and use it if so. As in Strife, the best armor is used up first.
|
||||||
|
BasicArmorPickup best = null;
|
||||||
|
Inventory probe = Owner.Inv;
|
||||||
|
while (probe != null)
|
||||||
|
{
|
||||||
|
let inInv = BasicArmorPickup(probe);
|
||||||
|
if (inInv != null)
|
||||||
|
{
|
||||||
|
if (best == null || best.SavePercent < inInv.SavePercent)
|
||||||
|
{
|
||||||
|
best = inInv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
probe = probe.Inv;
|
||||||
|
}
|
||||||
|
if (best != null)
|
||||||
|
{
|
||||||
|
Owner.UseInventory (best);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
damage = newdamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once the armor has absorbed its part of the damage, then apply its damage factor, if any, to the player
|
||||||
|
if ((damage > 0) && (ArmorType != 'None')) // BasicArmor is not going to have any damage factor, so skip it.
|
||||||
|
{
|
||||||
|
ApplyDamageFactors(ArmorType, damageType, damage, damage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// BasicArmorBonus
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
class BasicArmorBonus : Armor
|
class BasicArmorBonus : Armor
|
||||||
{
|
{
|
||||||
|
@ -119,7 +288,7 @@ class BasicArmorBonus : Armor
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
// This should really never happen but let's be prepared for a broken inventory.
|
// This should really never happen but let's be prepared for a broken inventory.
|
||||||
if (armor == NULL)
|
if (armor == null)
|
||||||
{
|
{
|
||||||
armor = BasicArmor(Spawn("BasicArmor"));
|
armor = BasicArmor(Spawn("BasicArmor"));
|
||||||
armor.BecomeItem ();
|
armor.BecomeItem ();
|
||||||
|
@ -152,7 +321,7 @@ class BasicArmorBonus : Armor
|
||||||
{ // Should never be less than 0, but might as well check anyway
|
{ // Should never be less than 0, but might as well check anyway
|
||||||
armor.Amount = 0;
|
armor.Amount = 0;
|
||||||
armor.Icon = Icon;
|
armor.Icon = Icon;
|
||||||
armor.SavePercent = clamp(SavePercent, 0, 100);
|
armor.SavePercent = clamp(SavePercent, 0, 100) / 100;
|
||||||
armor.MaxAbsorb = MaxAbsorb;
|
armor.MaxAbsorb = MaxAbsorb;
|
||||||
armor.ArmorType = GetClassName();
|
armor.ArmorType = GetClassName();
|
||||||
armor.MaxFullAbsorb = MaxFullAbsorb;
|
armor.MaxFullAbsorb = MaxFullAbsorb;
|
||||||
|
@ -167,21 +336,114 @@ class BasicArmorBonus : Armor
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BasicArmorPickup : Armor native
|
//===========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// BasicArmorPickup
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
class BasicArmorPickup : Armor
|
||||||
{
|
{
|
||||||
|
|
||||||
native double SavePercent;
|
double SavePercent;
|
||||||
native int MaxAbsorb;
|
int MaxAbsorb;
|
||||||
native int MaxFullAbsorb;
|
int MaxFullAbsorb;
|
||||||
native int SaveAmount;
|
int SaveAmount;
|
||||||
|
|
||||||
|
property prefix: Armor;
|
||||||
|
property SaveAmount : SaveAmount;
|
||||||
|
property SavePercent: SavePercent;
|
||||||
|
property MaxAbsorb: MaxAbsorb;
|
||||||
|
property MaxFullAbsorb: MaxFullAbsorb;
|
||||||
|
|
||||||
Default
|
Default
|
||||||
{
|
{
|
||||||
+Inventory.AUTOACTIVATE;
|
+Inventory.AUTOACTIVATE;
|
||||||
Inventory.MaxAmount 0;
|
Inventory.MaxAmount 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// ABasicArmorPickup :: CreateCopy
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override Inventory CreateCopy (Actor other)
|
||||||
|
{
|
||||||
|
let copy = BasicArmorPickup(Super.CreateCopy (other));
|
||||||
|
|
||||||
|
if (!bIgnoreSkill)
|
||||||
|
{
|
||||||
|
SaveAmount = int(SaveAmount * G_SkillPropertyFloat(SKILLP_ArmorFactor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy.SavePercent = SavePercent;
|
||||||
|
copy.SaveAmount = SaveAmount;
|
||||||
|
copy.MaxAbsorb = MaxAbsorb;
|
||||||
|
copy.MaxFullAbsorb = MaxFullAbsorb;
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// ABasicArmorPickup :: Use
|
||||||
|
//
|
||||||
|
// Either gives you new armor or replaces the armor you already have (if
|
||||||
|
// the SaveAmount is greater than the amount of armor you own). When the
|
||||||
|
// item is auto-activated, it will only be activated if its max amount is 0
|
||||||
|
// or if you have no armor active already.
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override bool Use (bool pickup)
|
||||||
|
{
|
||||||
|
let armor = BasicArmor(Owner.FindInventory("BasicArmor"));
|
||||||
|
|
||||||
|
// This should really never happen but let's be prepared for a broken inventory.
|
||||||
|
if (armor == null)
|
||||||
|
{
|
||||||
|
armor = BasicArmor(Spawn("BasicArmor"));
|
||||||
|
armor.BecomeItem ();
|
||||||
|
Owner.AddInventory (armor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If you already have more armor than this item gives you, you can't
|
||||||
|
// use it.
|
||||||
|
if (armor.Amount >= SaveAmount + armor.BonusCount)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Don't use it if you're picking it up and already have some.
|
||||||
|
if (pickup && armor.Amount > 0 && MaxAmount > 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
armor.SavePercent = clamp(SavePercent, 0, 100) / 100;
|
||||||
|
armor.Amount = SaveAmount + armor.BonusCount;
|
||||||
|
armor.MaxAmount = SaveAmount;
|
||||||
|
armor.Icon = Icon;
|
||||||
|
armor.MaxAbsorb = MaxAbsorb;
|
||||||
|
armor.MaxFullAbsorb = MaxFullAbsorb;
|
||||||
|
armor.ArmorType = GetClassName();
|
||||||
|
armor.ActualSaveAmount = SaveAmount;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// HexenArmor
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
class HexenArmor : Armor native
|
class HexenArmor : Armor native
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue