- did some cleanup and consolidation on damage factor code while converting it all to floating point.

- made armor properties floating point.
This commit is contained in:
Christoph Oelckers 2016-03-22 16:35:41 +01:00
parent 1eb106e2c5
commit af427b80bd
19 changed files with 104 additions and 112 deletions

View file

@ -1940,13 +1940,13 @@ static int PatchMisc (int dummy)
if (armor!=NULL) if (armor!=NULL)
{ {
armor->SaveAmount = 100 * deh.GreenAC; armor->SaveAmount = 100 * deh.GreenAC;
armor->SavePercent = deh.GreenAC == 1 ? FRACUNIT/3 : FRACUNIT/2; armor->SavePercent = deh.GreenAC == 1 ? 0.33335 : 0.5;
} }
armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("BlueArmor")); armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("BlueArmor"));
if (armor!=NULL) if (armor!=NULL)
{ {
armor->SaveAmount = 100 * deh.BlueAC; armor->SaveAmount = 100 * deh.BlueAC;
armor->SavePercent = deh.BlueAC == 1 ? FRACUNIT/3 : FRACUNIT/2; armor->SavePercent = deh.BlueAC == 1 ? 0.33335 : 0.5;
} }
ABasicArmorBonus *barmor; ABasicArmorBonus *barmor;

View file

@ -89,7 +89,7 @@ public:
FString Slot[10]; FString Slot[10];
FName InvulMode; FName InvulMode;
FName HealingRadiusType; FName HealingRadiusType;
fixed_t HexenArmor[5]; double HexenArmor[5];
BYTE ColorRangeStart; // Skin color range BYTE ColorRangeStart; // Skin color range
BYTE ColorRangeEnd; BYTE ColorRangeEnd;
FPlayerColorSetMap ColorSets; FPlayerColorSetMap ColorSets;

View file

@ -287,13 +287,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks)
// base the number of shards on the size of the dead thing, so bigger // base the number of shards on the size of the dead thing, so bigger
// things break up into more shards than smaller things. // things break up into more shards than smaller things.
// An actor with _f_radius() 20 and height 64 creates ~40 chunks. // An actor with _f_radius() 20 and height 64 creates ~40 chunks.
numChunks = MAX<int> (4, (self->_f_radius()>>FRACBITS)*(self->_f_height()>>FRACBITS)/32); numChunks = MAX<int>(4, int(self->radius * self->Height)/32);
i = (pr_freeze.Random2()) % (numChunks/4); i = (pr_freeze.Random2()) % (numChunks/4);
for (i = MAX (24, numChunks + i); i >= 0; i--) for (i = MAX (24, numChunks + i); i >= 0; i--)
{ {
fixed_t xo = (((pr_freeze() - 128)*self->_f_radius()) >> 7); double xo = (pr_freeze() - 128)*self->radius / 128;
fixed_t yo = (((pr_freeze() - 128)*self->_f_radius()) >> 7); double yo = (pr_freeze() - 128)*self->radius / 128;
fixed_t zo = (pr_freeze()*self->_f_height() / 255); double zo = (pr_freeze()*self->Height / 255);
mo = Spawn("IceChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); mo = Spawn("IceChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (mo) if (mo)
{ {

View file

@ -67,8 +67,8 @@ AInventory *ABasicArmor::CreateCopy (AActor *other)
{ {
// BasicArmor that is in use is stored in the inventory as BasicArmor. // BasicArmor that is in use is stored in the inventory as BasicArmor.
// BasicArmor that is in reserve is not. // BasicArmor that is in reserve is not.
ABasicArmor *copy = Spawn<ABasicArmor> (0, 0, 0, NO_REPLACE); ABasicArmor *copy = Spawn<ABasicArmor> ();
copy->SavePercent = SavePercent != 0 ? SavePercent : FRACUNIT/3; copy->SavePercent = SavePercent != 0 ? SavePercent : 0.33335; // slightly more than 1/3 to avoid roundoff errors.
copy->Amount = Amount; copy->Amount = Amount;
copy->MaxAmount = MaxAmount; copy->MaxAmount = MaxAmount;
copy->Icon = Icon; copy->Icon = Icon;
@ -130,7 +130,7 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
} }
else else
{ {
saved = full + FixedMul (damage - full, SavePercent); saved = full + int((damage - full) * SavePercent);
if (MaxAbsorb > 0 && saved + AbsorbCount > MaxAbsorb) if (MaxAbsorb > 0 && saved + AbsorbCount > MaxAbsorb)
{ {
saved = MAX(0, MaxAbsorb - AbsorbCount); saved = MAX(0, MaxAbsorb - AbsorbCount);
@ -179,15 +179,10 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
// This code is taken and adapted from APowerProtection::ModifyDamage(). // This code is taken and adapted from APowerProtection::ModifyDamage().
// The differences include not using a default value, and of course the way // The differences include not using a default value, and of course the way
// the damage factor info is obtained. // the damage factor info is obtained.
const fixed_t *pdf = NULL;
DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors; DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors;
if (df != NULL && df->CountUsed() != 0) if (df != NULL)
{ {
pdf = df->CheckFactor(damageType); damage = newdamage = df->Apply(damageType, damage);
if (pdf != NULL)
{
damage = newdamage = FixedMul(damage, *pdf);
}
} }
} }
if (Inventory != NULL) if (Inventory != NULL)
@ -401,7 +396,7 @@ AInventory *AHexenArmor::CreateCopy (AActor *other)
// Like BasicArmor, HexenArmor is used in the inventory but not the map. // Like BasicArmor, HexenArmor is used in the inventory but not the map.
// health is the slot this armor occupies. // health is the slot this armor occupies.
// Amount is the quantity to give (0 = normal max). // Amount is the quantity to give (0 = normal max).
AHexenArmor *copy = Spawn<AHexenArmor> (0, 0, 0, NO_REPLACE); AHexenArmor *copy = Spawn<AHexenArmor> ();
copy->AddArmorToSlot (other, health, Amount); copy->AddArmorToSlot (other, health, Amount);
GoAwayAndDie (); GoAwayAndDie ();
return copy; return copy;
@ -452,7 +447,7 @@ bool AHexenArmor::HandlePickup (AInventory *item)
bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount) bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount)
{ {
APlayerPawn *ppawn; APlayerPawn *ppawn;
int hits; double hits;
if (actor->player != NULL) if (actor->player != NULL)
{ {
@ -478,9 +473,9 @@ bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount)
} }
else else
{ {
hits = amount * 5 * FRACUNIT; hits = amount * 5;
fixed_t total = Slots[0]+Slots[1]+Slots[2]+Slots[3]+Slots[4]; auto total = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
fixed_t max = SlotsIncrement[0]+SlotsIncrement[1]+SlotsIncrement[2]+SlotsIncrement[3]+Slots[4]+4*5*FRACUNIT; auto max = SlotsIncrement[0] + SlotsIncrement[1] + SlotsIncrement[2] + SlotsIncrement[3] + Slots[4] + 4 * 5;
if (total < max) if (total < max)
{ {
Slots[slot] += hits; Slots[slot] += hits;
@ -500,13 +495,13 @@ void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
{ {
if (!DamageTypeDefinition::IgnoreArmor(damageType)) if (!DamageTypeDefinition::IgnoreArmor(damageType))
{ {
fixed_t savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4]; double savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
if (savedPercent) if (savedPercent)
{ // armor absorbed some damage { // armor absorbed some damage
if (savedPercent > 100*FRACUNIT) if (savedPercent > 100)
{ {
savedPercent = 100*FRACUNIT; savedPercent = 100;
} }
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
@ -516,15 +511,8 @@ void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
// with the dragon skin bracers. // with the dragon skin bracers.
if (damage < 10000) if (damage < 10000)
{ {
#if __APPLE__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ == 1 Slots[i] -= damage * SlotsIncrement[i] / 300.;
// -O1 optimizer bug work around. Only needed for if (Slots[i] < 2)
// GCC 4.2.1 on OS X for 10.4/10.5 tools compatibility.
volatile fixed_t tmp = 300;
Slots[i] -= ::Scale (damage, SlotsIncrement[i], tmp);
#else
Slots[i] -= ::Scale (damage, SlotsIncrement[i], 300);
#endif
if (Slots[i] < 2*FRACUNIT)
{ {
Slots[i] = 0; Slots[i] = 0;
} }
@ -535,10 +523,10 @@ void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
} }
} }
} }
int saved = ::Scale (damage, savedPercent, 100*FRACUNIT); int saved = int(damage * savedPercent / 100.);
if (saved > savedPercent >> (FRACBITS-1)) if (saved > savedPercent*2)
{ {
saved = savedPercent >> (FRACBITS-1); saved = int(savedPercent*2);
} }
newdamage -= saved; newdamage -= saved;
damage = newdamage; damage = newdamage;

View file

@ -1630,25 +1630,20 @@ void APowerDamage::EndEffect( )
void APowerDamage::ModifyDamage(int damage, FName damageType, int &newdamage, bool passive) void APowerDamage::ModifyDamage(int damage, FName damageType, int &newdamage, bool passive)
{ {
static const fixed_t def = 4*FRACUNIT;
if (!passive && damage > 0) if (!passive && damage > 0)
{ {
const fixed_t *pdf = NULL; int newdam;
DmgFactors *df = GetClass()->DamageFactors; DmgFactors *df = GetClass()->DamageFactors;
if (df != NULL && df->CountUsed() != 0) if (df != NULL && df->CountUsed() != 0)
{ {
pdf = df->CheckFactor(damageType); newdam = MIN(1, df->Apply(damageType, damage));// don't allow zero damage as result of an underflow
} }
else else
{ {
pdf = &def; newdam = damage * 4;
}
if (pdf != NULL)
{
damage = newdamage = FixedMul(damage, *pdf);
if (*pdf > 0 && damage == 0) damage = newdamage = 1; // don't allow zero damage as result of an underflow
if (Owner != NULL && *pdf > FRACUNIT) S_Sound(Owner, 5, ActiveSound, 1.0f, ATTN_NONE);
} }
if (Owner != NULL && newdam > damage) S_Sound(Owner, 5, ActiveSound, 1.0f, ATTN_NONE);
newdamage = newdam;
} }
if (Inventory != NULL) Inventory->ModifyDamage(damage, damageType, newdamage, passive); if (Inventory != NULL) Inventory->ModifyDamage(damage, damageType, newdamage, passive);
} }
@ -1710,22 +1705,20 @@ void APowerProtection::EndEffect( )
void APowerProtection::ModifyDamage(int damage, FName damageType, int &newdamage, bool passive) void APowerProtection::ModifyDamage(int damage, FName damageType, int &newdamage, bool passive)
{ {
static const fixed_t def = FRACUNIT/4;
if (passive && damage > 0) if (passive && damage > 0)
{ {
const fixed_t *pdf = NULL; int newdam;
DmgFactors *df = GetClass()->DamageFactors; DmgFactors *df = GetClass()->DamageFactors;
if (df != NULL && df->CountUsed() != 0) if (df != NULL && df->CountUsed() != 0)
{ {
pdf = df->CheckFactor(damageType); newdam = MIN(0, df->Apply(damageType, damage));
} }
else pdf = &def; else
if (pdf != NULL)
{ {
damage = newdamage = FixedMul(damage, *pdf); newdam = damage / 4;
if (Owner != NULL && *pdf < FRACUNIT) S_Sound(Owner, CHAN_AUTO, ActiveSound, 1.0f, ATTN_NONE);
} }
if (Owner != NULL && newdam < damage) S_Sound(Owner, CHAN_AUTO, ActiveSound, 1.0f, ATTN_NONE);
newdamage = newdam;
} }
if (Inventory != NULL) if (Inventory != NULL)
{ {

View file

@ -456,7 +456,7 @@ public:
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); virtual void AbsorbDamage (int damage, FName damageType, int &newdamage);
int AbsorbCount; int AbsorbCount;
fixed_t SavePercent; double SavePercent;
int MaxAbsorb; int MaxAbsorb;
int MaxFullAbsorb; int MaxFullAbsorb;
int BonusCount; int BonusCount;
@ -473,7 +473,7 @@ public:
virtual AInventory *CreateCopy (AActor *other); virtual AInventory *CreateCopy (AActor *other);
virtual bool Use (bool pickup); virtual bool Use (bool pickup);
fixed_t SavePercent; double SavePercent;
int MaxAbsorb; int MaxAbsorb;
int MaxFullAbsorb; int MaxFullAbsorb;
int SaveAmount; int SaveAmount;
@ -488,7 +488,7 @@ public:
virtual AInventory *CreateCopy (AActor *other); virtual AInventory *CreateCopy (AActor *other);
virtual bool Use (bool pickup); virtual bool Use (bool pickup);
fixed_t SavePercent; // The default, for when you don't already have armor double SavePercent; // The default, for when you don't already have armor
int MaxSaveAmount; int MaxSaveAmount;
int MaxAbsorb; int MaxAbsorb;
int MaxFullAbsorb; int MaxFullAbsorb;
@ -510,8 +510,8 @@ public:
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); virtual void AbsorbDamage (int damage, FName damageType, int &newdamage);
void DepleteOrDestroy(); void DepleteOrDestroy();
fixed_t Slots[5]; double Slots[5];
fixed_t SlotsIncrement[4]; double SlotsIncrement[4];
protected: protected:
bool AddArmorToSlot (AActor *actor, int slot, int amount); bool AddArmorToSlot (AActor *actor, int slot, int amount);

View file

@ -146,7 +146,7 @@ void ASoundSequence::PostBeginPlay ()
} }
if (master == NULL) if (master == NULL)
{ {
master = Spawn<ASoundSequenceSlot> (0, 0, 0, NO_REPLACE); master = Spawn<ASoundSequenceSlot> ();
master->Sequence = SN_StartSequence (master, slot, 0); master->Sequence = SN_StartSequence (master, slot, 0);
GC::WriteBarrier(master, master->Sequence); GC::WriteBarrier(master, master->Sequence);
} }

View file

@ -282,7 +282,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
if (harmor->Slots[armorType] > 0 && harmor->SlotsIncrement[armorType] > 0) if (harmor->Slots[armorType] > 0 && harmor->SlotsIncrement[armorType] > 0)
{ {
//combine the alpha values //combine the alpha values
alpha = FixedMul(alpha, MIN<fixed_t> (OPAQUE, Scale(harmor->Slots[armorType], OPAQUE, harmor->SlotsIncrement[armorType]))); alpha = int(alpha * MIN(1., harmor->Slots[armorType] / harmor->SlotsIncrement[armorType]));
texture = statusBar->Images[image]; texture = statusBar->Images[image];
} }
else else
@ -1377,21 +1377,21 @@ class CommandDrawNumber : public CommandDrawString
case ARMORCLASS: case ARMORCLASS:
case SAVEPERCENT: case SAVEPERCENT:
{ {
double add = 0;
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>(); AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>();
if(harmor != NULL) if(harmor != NULL)
{ {
num = harmor->Slots[0] + harmor->Slots[1] + add = harmor->Slots[0] + harmor->Slots[1] +
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]; harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4];
} }
//Hexen counts basic armor also so we should too. //Hexen counts basic armor also so we should too.
if(statusBar->armor != NULL) if(statusBar->armor != NULL)
{ {
num += FixedMul(statusBar->armor->SavePercent, 100*FRACUNIT); add += statusBar->armor->SavePercent * 100;
} }
if(value == ARMORCLASS) if(value == ARMORCLASS)
num /= (5*FRACUNIT); add /= 5;
else num = int(add);
num >>= FRACBITS;
break; break;
} }
case GLOBALVAR: case GLOBALVAR:
@ -2770,18 +2770,19 @@ class CommandDrawBar : public SBarInfoCommand
} }
case SAVEPERCENT: case SAVEPERCENT:
{ {
double add = 0;
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>(); AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>();
if(harmor != NULL) if(harmor != NULL)
{ {
value = harmor->Slots[0] + harmor->Slots[1] + add = harmor->Slots[0] + harmor->Slots[1] +
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]; harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4];
} }
//Hexen counts basic armor also so we should too. //Hexen counts basic armor also so we should too.
if(statusBar->armor != NULL) if(statusBar->armor != NULL)
{ {
value += FixedMul(statusBar->armor->SavePercent, 100*FRACUNIT); add += statusBar->armor->SavePercent * 100;
} }
value >>= FRACBITS; value = int(add);
max = 100; max = 100;
break; break;
} }

View file

@ -313,9 +313,8 @@ static void DrawArmor(ABasicArmor * barmor, AHexenArmor * harmor, int x, int y)
if (harmor) if (harmor)
{ {
int ac = (harmor->Slots[0] + harmor->Slots[1] + harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]); auto ac = (harmor->Slots[0] + harmor->Slots[1] + harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]);
ac >>= FRACBITS; ap += int(ac);
ap += ac;
if (ac) if (ac)
{ {

View file

@ -279,7 +279,7 @@ void FMapInfoParser::ParseGameInfo()
if (sc.CheckToken(',')) if (sc.CheckToken(','))
{ {
sc.MustGetToken(TK_FloatConst); sc.MustGetToken(TK_FloatConst);
gameinfo.Armor2Percent = FLOAT2FIXED(sc.Float); gameinfo.Armor2Percent = sc.Float;
sc.MustGetToken(','); sc.MustGetToken(',');
sc.MustGetToken(TK_StringConst); sc.MustGetToken(TK_StringConst);
gameinfo.ArmorIcon2 = sc.String; gameinfo.ArmorIcon2 = sc.String;

View file

@ -135,7 +135,7 @@ struct gameinfo_t
FString ArmorIcon2; FString ArmorIcon2;
FString PauseSign; FString PauseSign;
FString Endoom; FString Endoom;
fixed_t Armor2Percent; double Armor2Percent;
FString quitSound; FString quitSound;
gameborder_t Border; gameborder_t Border;
double telefogheight; double telefogheight;

View file

@ -532,7 +532,7 @@ PClassActor *PClassActor::GetReplacee(bool lookskill)
// //
//========================================================================== //==========================================================================
void PClassActor::SetDamageFactor(FName type, fixed_t factor) void PClassActor::SetDamageFactor(FName type, double factor)
{ {
if (DamageFactors == NULL) if (DamageFactors == NULL)
{ {
@ -593,16 +593,18 @@ void PClassActor::ReplaceClassRef(PClass *oldclass, PClass *newclass)
// //
//========================================================================== //==========================================================================
fixed_t *DmgFactors::CheckFactor(FName type) int DmgFactors::Apply(FName type, int damage)
{ {
fixed_t *pdf = CheckKey(type); auto pdf = CheckKey(type);
if (pdf == NULL && type != NAME_None) if (pdf == NULL && type != NAME_None)
{ {
pdf = CheckKey(NAME_None); pdf = CheckKey(NAME_None);
} }
return pdf; if (!pdf) return damage;
return int(damage * *pdf);
} }
static void SummonActor (int command, int command2, FCommandLine argv) static void SummonActor (int command, int command2, FCommandLine argv)
{ {
if (CheckCheatmode ()) if (CheckCheatmode ())
@ -689,32 +691,33 @@ bool DamageTypeDefinition::IgnoreArmor(FName type)
// //
//========================================================================== //==========================================================================
int DamageTypeDefinition::ApplyMobjDamageFactor(int damage, FName type, DmgFactors const * const factors) double DamageTypeDefinition::GetMobjDamageFactor(FName type, DmgFactors const * const factors)
{ {
if (factors) if (factors)
{ {
// If the actor has named damage factors, look for a specific factor // If the actor has named damage factors, look for a specific factor
fixed_t const *pdf = factors->CheckKey(type);
if (pdf) return FixedMul(damage, *pdf); // type specific damage type auto pdf = factors->CheckKey(type);
if (pdf) return *pdf; // type specific damage type
// If this was nonspecific damage, don't fall back to nonspecific search // If this was nonspecific damage, don't fall back to nonspecific search
if (type == NAME_None) return damage; if (type == NAME_None) return 1.;
} }
// If this was nonspecific damage, don't fall back to nonspecific search // If this was nonspecific damage, don't fall back to nonspecific search
else if (type == NAME_None) else if (type == NAME_None)
{ {
return damage; return 1.;
} }
else else
{ {
// Normal is unsupplied / 1.0, so there's no difference between modifying and overriding // Normal is unsupplied / 1.0, so there's no difference between modifying and overriding
DamageTypeDefinition *dtd = Get(type); DamageTypeDefinition *dtd = Get(type);
return dtd ? FixedMul(damage, dtd->DefaultFactor) : damage; return dtd ? dtd->DefaultFactor : 1.;
} }
{ {
fixed_t const *pdf = factors->CheckKey(NAME_None); auto pdf = factors->CheckKey(NAME_None);
DamageTypeDefinition *dtd = Get(type); DamageTypeDefinition *dtd = Get(type);
// Here we are looking for modifications to untyped damage // Here we are looking for modifications to untyped damage
// If the calling actor defines untyped damage factor, that is contained in "pdf". // If the calling actor defines untyped damage factor, that is contained in "pdf".
@ -722,15 +725,21 @@ int DamageTypeDefinition::ApplyMobjDamageFactor(int damage, FName type, DmgFacto
{ {
if (dtd) if (dtd)
{ {
if (dtd->ReplaceFactor) return FixedMul(damage, dtd->DefaultFactor); // use default instead of untyped factor if (dtd->ReplaceFactor) return dtd->DefaultFactor; // use default instead of untyped factor
return FixedMul(damage, FixedMul(*pdf, dtd->DefaultFactor)); // use default as modification of untyped factor return *pdf * dtd->DefaultFactor; // use default as modification of untyped factor
} }
return FixedMul(damage, *pdf); // there was no default, so actor default is used return *pdf; // there was no default, so actor default is used
} }
else if (dtd) else if (dtd)
{ {
return FixedMul(damage, dtd->DefaultFactor); // implicit untyped factor 1.0 does not need to be applied/replaced explicitly return dtd->DefaultFactor; // implicit untyped factor 1.0 does not need to be applied/replaced explicitly
} }
} }
return damage; return 1.;
}
int DamageTypeDefinition::ApplyMobjDamageFactor(int damage, FName type, DmgFactors const * const factors)
{
double factor = GetMobjDamageFactor(type, factors);
return int(damage * factor);
} }

View file

@ -158,9 +158,9 @@ FArchive &operator<< (FArchive &arc, FState *&state);
#include "gametype.h" #include "gametype.h"
struct DmgFactors : public TMap<FName, fixed_t> struct DmgFactors : public TMap<FName, double>
{ {
fixed_t *CheckFactor(FName type); int Apply(FName type, int damage);
}; };
typedef TMap<FName, int> PainChanceList; typedef TMap<FName, int> PainChanceList;
@ -169,20 +169,21 @@ struct DamageTypeDefinition
public: public:
DamageTypeDefinition() { Clear(); } DamageTypeDefinition() { Clear(); }
fixed_t DefaultFactor; double DefaultFactor;
bool ReplaceFactor; bool ReplaceFactor;
bool NoArmor; bool NoArmor;
void Apply(FName type); void Apply(FName type);
void Clear() void Clear()
{ {
DefaultFactor = FRACUNIT; DefaultFactor = 1.;
ReplaceFactor = false; ReplaceFactor = false;
NoArmor = false; NoArmor = false;
} }
static DamageTypeDefinition *Get(FName type); 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);
}; };
@ -206,7 +207,7 @@ public:
void BuildDefaults(); void BuildDefaults();
void ApplyDefaults(BYTE *defaults); void ApplyDefaults(BYTE *defaults);
void RegisterIDs(); void RegisterIDs();
void SetDamageFactor(FName type, fixed_t factor); void SetDamageFactor(FName type, double factor);
void SetPainChance(FName type, int chance); void SetPainChance(FName type, int chance);
size_t PropagateMark(); size_t PropagateMark();
void InitializeNativeDefaults(); void InitializeNativeDefaults();

View file

@ -715,7 +715,7 @@ void cht_Give (player_t *player, const char *name, int amount)
{ {
ABasicArmorPickup *armor = Spawn<ABasicArmorPickup> (); ABasicArmorPickup *armor = Spawn<ABasicArmorPickup> ();
armor->SaveAmount = 100*deh.BlueAC; armor->SaveAmount = 100*deh.BlueAC;
armor->SavePercent = gameinfo.Armor2Percent > 0? gameinfo.Armor2Percent : FRACUNIT/2; armor->SavePercent = gameinfo.Armor2Percent > 0? gameinfo.Armor2Percent : 0.5;
if (!armor->CallTryPickup (player->mo)) if (!armor->CallTryPickup (player->mo))
{ {
armor->Destroy (); armor->Destroy ();

View file

@ -5080,7 +5080,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
return equippedarmor->MaxAmount; return equippedarmor->MaxAmount;
case ARMORINFO_SAVEPERCENT: case ARMORINFO_SAVEPERCENT:
return equippedarmor->SavePercent; return DoubleToACS(equippedarmor->SavePercent);
case ARMORINFO_MAXABSORB: case ARMORINFO_MAXABSORB:
return equippedarmor->MaxAbsorb; return equippedarmor->MaxAbsorb;

View file

@ -3317,13 +3317,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst)
// base the number of shards on the size of the dead thing, so bigger // base the number of shards on the size of the dead thing, so bigger
// things break up into more shards than smaller things. // things break up into more shards than smaller things.
// An self with _f_radius() 20 and height 64 creates ~40 chunks. // An self with _f_radius() 20 and height 64 creates ~40 chunks.
numChunks = MAX<int> (4, int(self->radius * self->Height)); numChunks = MAX<int> (4, int(self->radius * self->Height)/32);
i = (pr_burst.Random2()) % (numChunks/4); i = (pr_burst.Random2()) % (numChunks/4);
for (i = MAX (24, numChunks + i); i >= 0; i--) for (i = MAX (24, numChunks + i); i >= 0; i--)
{ {
fixed_t xo = (((pr_burst() - 128)*self->_f_radius()) >> 7); double xo = (pr_burst() - 128) * self->radius / 128;
fixed_t yo = (((pr_burst() - 128)*self->_f_radius()) >> 7); double yo = (pr_burst() - 128) * self->radius / 128;
fixed_t zo = (pr_burst()*self->_f_height() / 255 + self->GetBobOffset()); double zo = (pr_burst() * self->Height / 255);
mo = Spawn(chunk, self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); mo = Spawn(chunk, self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (mo) if (mo)

View file

@ -1283,8 +1283,8 @@ static void ParseDamageDefinition(FScanner &sc)
if (sc.Compare("FACTOR")) if (sc.Compare("FACTOR"))
{ {
sc.MustGetFloat(); sc.MustGetFloat();
dtd.DefaultFactor = FLOAT2FIXED(sc.Float); dtd.DefaultFactor = sc.Float;
if (!dtd.DefaultFactor) dtd.ReplaceFactor = true; // Multiply by 0 yields 0: FixedMul(damage, FixedMul(factor, 0)) is more wasteful than FixedMul(factor, 0) if (dtd.DefaultFactor == 0) dtd.ReplaceFactor = true; // Multiply by 0 yields 0: FixedMul(damage, FixedMul(factor, 0)) is more wasteful than FixedMul(factor, 0)
} }
else if (sc.Compare("REPLACEFACTOR")) else if (sc.Compare("REPLACEFACTOR"))
{ {

View file

@ -254,7 +254,7 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in
defaults->Gravity = set ? 1. / 4 : 1.; defaults->Gravity = set ? 1. / 4 : 1.;
break; break;
case DEPF_FIRERESIST: case DEPF_FIRERESIST:
info->SetDamageFactor(NAME_Fire, set? FRACUNIT/2 : FRACUNIT); info->SetDamageFactor(NAME_Fire, set ? 0.5 : 1.);
break; break;
// the bounce flags will set the compatibility bounce modes to remain compatible // the bounce flags will set the compatibility bounce modes to remain compatible
case DEPF_HERETICBOUNCE: case DEPF_HERETICBOUNCE:
@ -322,8 +322,8 @@ bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index)
case DEPF_FIRERESIST: case DEPF_FIRERESIST:
if (info->DamageFactors) if (info->DamageFactors)
{ {
fixed_t *df = info->DamageFactors->CheckKey(NAME_Fire); double *df = info->DamageFactors->CheckKey(NAME_Fire);
return df && (*df) == FRACUNIT / 2; return df && (*df) == 0.5;
} }
return false; return false;
@ -1229,7 +1229,7 @@ DEFINE_PROPERTY(damagefactor, ZF, Actor)
if (!stricmp(str, "Normal")) dmgType = NAME_None; if (!stricmp(str, "Normal")) dmgType = NAME_None;
else dmgType=str; else dmgType=str;
info->SetDamageFactor(dmgType, FLOAT2FIXED(id)); info->SetDamageFactor(dmgType, id);
} }
} }
@ -1639,9 +1639,9 @@ DEFINE_CLASS_PROPERTY(saveamount, I, Armor)
//========================================================================== //==========================================================================
DEFINE_CLASS_PROPERTY(savepercent, F, Armor) DEFINE_CLASS_PROPERTY(savepercent, F, Armor)
{ {
PROP_FIXED_PARM(i, 0); PROP_DOUBLE_PARM(i, 0);
i = clamp(i, 0, 100*FRACUNIT)/100; i = clamp(i, 0., 100.)/100.;
// Special case here because this property has to work for 2 unrelated classes // Special case here because this property has to work for 2 unrelated classes
if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
{ {
@ -2793,7 +2793,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
PROP_FIXED_PARM(val, i); PROP_DOUBLE_PARM(val, i);
static_cast<PClassPlayerPawn *>(info)->HexenArmor[i] = val; static_cast<PClassPlayerPawn *>(info)->HexenArmor[i] = val;
} }
} }

View file

@ -105,7 +105,7 @@ ACTOR BasicArmorBonus : Armor native
+Inventory.AUTOACTIVATE +Inventory.AUTOACTIVATE
+Inventory.ALWAYSPICKUP +Inventory.ALWAYSPICKUP
Inventory.MaxAmount 0 Inventory.MaxAmount 0
Armor.SavePercent 0.333333 Armor.SavePercent 33.335
} }