mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-23 12:22:45 +00:00
- scriptified HexenArmor.
This commit is contained in:
parent
2fcffd1fc1
commit
632a29e365
12 changed files with 217 additions and 242 deletions
|
@ -46,7 +46,6 @@
|
||||||
#include "cmdlib.h"
|
#include "cmdlib.h"
|
||||||
|
|
||||||
IMPLEMENT_CLASS(AArmor, false, false)
|
IMPLEMENT_CLASS(AArmor, false, false)
|
||||||
IMPLEMENT_CLASS(AHexenArmor, false, false)
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
|
@ -56,178 +55,3 @@ IMPLEMENT_CLASS(AHexenArmor, false, false)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
//
|
|
||||||
// AHexenArmor :: DepleteOrDestroy
|
|
||||||
//
|
|
||||||
//===========================================================================
|
|
||||||
|
|
||||||
void AHexenArmor::DepleteOrDestroy()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
Slots[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,24 +8,3 @@ class AArmor : public AInventory
|
||||||
DECLARE_CLASS (AArmor, AInventory)
|
DECLARE_CLASS (AArmor, AInventory)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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) override;
|
|
||||||
virtual AInventory *CreateCopy (AActor *other) override;
|
|
||||||
virtual AInventory *CreateTossable () override;
|
|
||||||
virtual bool HandlePickup (AInventory *item) override;
|
|
||||||
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
|
|
||||||
virtual void DepleteOrDestroy() override;
|
|
||||||
|
|
||||||
double Slots[5];
|
|
||||||
double SlotsIncrement[4];
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool AddArmorToSlot (AActor *actor, int slot, int amount);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
|
@ -1051,19 +1051,10 @@ void AInventory::OnDestroy ()
|
||||||
|
|
||||||
void AInventory::DepleteOrDestroy ()
|
void AInventory::DepleteOrDestroy ()
|
||||||
{
|
{
|
||||||
// If it's not ammo or an internal armor, destroy it.
|
IFVIRTUAL(AInventory, DepleteOrDestroy)
|
||||||
// Ammo needs to stick around, even when it's zero for the benefit
|
|
||||||
// of the weapons that use it and to maintain the maximum ammo
|
|
||||||
// amounts a backpack might have given.
|
|
||||||
// Armor shouldn't be removed because they only work properly when
|
|
||||||
// they are the last items in the inventory.
|
|
||||||
if (ItemFlags & IF_KEEPDEPLETED)
|
|
||||||
{
|
{
|
||||||
Amount = 0;
|
VMValue params[1] = { (DObject*)this };
|
||||||
}
|
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
|
||||||
else
|
|
||||||
{
|
|
||||||
Destroy();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ public:
|
||||||
|
|
||||||
// virtual methods that only get overridden by special internal classes, like DehackedPickup.
|
// virtual methods that only get overridden by special internal classes, like DehackedPickup.
|
||||||
// There is no need to expose these to scripts.
|
// There is no need to expose these to scripts.
|
||||||
virtual void DepleteOrDestroy ();
|
void DepleteOrDestroy ();
|
||||||
virtual bool ShouldRespawn ();
|
virtual bool ShouldRespawn ();
|
||||||
virtual void DoPickupSpecial (AActor *toucher);
|
virtual void DoPickupSpecial (AActor *toucher);
|
||||||
|
|
||||||
|
|
|
@ -364,10 +364,11 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
|
||||||
}
|
}
|
||||||
pmo->Destroy ();
|
pmo->Destroy ();
|
||||||
// Restore playerclass armor to its normal amount.
|
// Restore playerclass armor to its normal amount.
|
||||||
AHexenArmor *hxarmor = mo->FindInventory<AHexenArmor>();
|
auto hxarmor = mo->FindInventory(NAME_HexenArmor);
|
||||||
if (hxarmor != nullptr)
|
if (hxarmor != nullptr)
|
||||||
{
|
{
|
||||||
hxarmor->Slots[4] = mo->GetClass()->HexenArmor[0];
|
double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr);
|
||||||
|
Slots[4] = mo->GetClass()->HexenArmor[0];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,13 +276,15 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
|
||||||
{
|
{
|
||||||
int armorType = type - HEXENARMOR_ARMOR;
|
int armorType = type - HEXENARMOR_ARMOR;
|
||||||
|
|
||||||
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>();
|
auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor);
|
||||||
if (harmor != NULL)
|
if (harmor != NULL)
|
||||||
{
|
{
|
||||||
if (harmor->Slots[armorType] > 0 && harmor->SlotsIncrement[armorType] > 0)
|
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||||
|
double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr);
|
||||||
|
if (Slots[armorType] > 0 && SlotsIncrement[armorType] > 0)
|
||||||
{
|
{
|
||||||
//combine the alpha values
|
//combine the alpha values
|
||||||
alpha *= MIN(1., harmor->Slots[armorType] / harmor->SlotsIncrement[armorType]);
|
alpha *= MIN(1., Slots[armorType] / SlotsIncrement[armorType]);
|
||||||
texture = statusBar->Images[image];
|
texture = statusBar->Images[image];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1409,11 +1411,11 @@ class CommandDrawNumber : public CommandDrawString
|
||||||
case SAVEPERCENT:
|
case SAVEPERCENT:
|
||||||
{
|
{
|
||||||
double add = 0;
|
double add = 0;
|
||||||
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>();
|
auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor);
|
||||||
if(harmor != NULL)
|
if(harmor != NULL)
|
||||||
{
|
{
|
||||||
add = harmor->Slots[0] + harmor->Slots[1] +
|
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||||
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4];
|
add = Slots[0] + Slots[1] + Slots[2] + Slots[3] + 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)
|
||||||
|
@ -2842,12 +2844,13 @@ class CommandDrawBar : public SBarInfoCommand
|
||||||
case SAVEPERCENT:
|
case SAVEPERCENT:
|
||||||
{
|
{
|
||||||
double add = 0;
|
double add = 0;
|
||||||
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>();
|
auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor);
|
||||||
if(harmor != NULL)
|
if (harmor != NULL)
|
||||||
{
|
{
|
||||||
add = harmor->Slots[0] + harmor->Slots[1] +
|
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||||
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4];
|
add = Slots[0] + Slots[1] + Slots[2] + Slots[3] + 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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -310,14 +310,15 @@ static void DrawHealth(player_t *CPlayer, int x, int y)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
static void DrawArmor(AInventory * barmor, AHexenArmor * harmor, int x, int y)
|
static void DrawArmor(AInventory * barmor, AInventory * harmor, int x, int y)
|
||||||
{
|
{
|
||||||
int ap = 0;
|
int ap = 0;
|
||||||
int bestslot = 4;
|
int bestslot = 4;
|
||||||
|
|
||||||
if (harmor)
|
if (harmor)
|
||||||
{
|
{
|
||||||
auto ac = (harmor->Slots[0] + harmor->Slots[1] + harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]);
|
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||||
|
auto ac = (Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4]);
|
||||||
ap += int(ac);
|
ap += int(ac);
|
||||||
|
|
||||||
if (ac)
|
if (ac)
|
||||||
|
@ -326,7 +327,7 @@ static void DrawArmor(AInventory * barmor, AHexenArmor * harmor, int x, int y)
|
||||||
bestslot = 0;
|
bestslot = 0;
|
||||||
for (int i = 1; i < 4; ++i)
|
for (int i = 1; i < 4; ++i)
|
||||||
{
|
{
|
||||||
if (harmor->Slots[i] > harmor->Slots[bestslot])
|
if (Slots[i] > Slots[bestslot])
|
||||||
{
|
{
|
||||||
bestslot = i;
|
bestslot = i;
|
||||||
}
|
}
|
||||||
|
@ -1141,8 +1142,7 @@ void DrawHUD()
|
||||||
DrawFrags(CPlayer, 5, hudheight-70);
|
DrawFrags(CPlayer, 5, hudheight-70);
|
||||||
}
|
}
|
||||||
DrawHealth(CPlayer, 5, hudheight-45);
|
DrawHealth(CPlayer, 5, hudheight-45);
|
||||||
DrawArmor(CPlayer->mo->FindInventory(NAME_BasicArmor),
|
DrawArmor(CPlayer->mo->FindInventory(NAME_BasicArmor), CPlayer->mo->FindInventory(NAME_HexenArmor), 5, hudheight-20);
|
||||||
CPlayer->mo->FindInventory<AHexenArmor>(), 5, hudheight-20);
|
|
||||||
i=DrawKeys(CPlayer, hudwidth-4, hudheight-10);
|
i=DrawKeys(CPlayer, hudwidth-4, hudheight-10);
|
||||||
i=DrawAmmo(CPlayer, hudwidth-5, i);
|
i=DrawAmmo(CPlayer, hudwidth-5, i);
|
||||||
if (hud_showweapons) DrawWeapons(CPlayer, hudwidth - 5, i);
|
if (hud_showweapons) DrawWeapons(CPlayer, hudwidth - 5, i);
|
||||||
|
|
|
@ -92,6 +92,9 @@ xx(MaxFullAbsorb)
|
||||||
xx(MaxAmount)
|
xx(MaxAmount)
|
||||||
xx(ActualSaveAmount)
|
xx(ActualSaveAmount)
|
||||||
xx(ArmorType)
|
xx(ArmorType)
|
||||||
|
xx(HexenArmor)
|
||||||
|
xx(Slots)
|
||||||
|
xx(SlotsIncrement)
|
||||||
|
|
||||||
|
|
||||||
xx(BulletPuff)
|
xx(BulletPuff)
|
||||||
|
|
|
@ -894,9 +894,6 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->IsKindOf(RUNTIME_CLASS(AHexenArmor)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Do not take ammo if the "no take infinite/take as ammo depletion" flag is set
|
// Do not take ammo if the "no take infinite/take as ammo depletion" flag is set
|
||||||
// and infinite ammo is on
|
// and infinite ammo is on
|
||||||
if (notakeinfinite &&
|
if (notakeinfinite &&
|
||||||
|
|
|
@ -1153,12 +1153,11 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
|
||||||
item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent);
|
item->IntVar(NAME_SavePercent) = defitem->IntVar(NAME_SavePercent);
|
||||||
item->Amount = defitem->Amount;
|
item->Amount = defitem->Amount;
|
||||||
}
|
}
|
||||||
else if (item->IsKindOf(RUNTIME_CLASS(AHexenArmor)))
|
else if (item->IsKindOf(PClass::FindActor(NAME_HexenArmor)))
|
||||||
{
|
{
|
||||||
static_cast<AHexenArmor*>(item)->Slots[0] = static_cast<AHexenArmor*>(defitem)->Slots[0];
|
double *SlotsTo = (double*)item->ScriptVar(NAME_Slots, nullptr);
|
||||||
static_cast<AHexenArmor*>(item)->Slots[1] = static_cast<AHexenArmor*>(defitem)->Slots[1];
|
double *SlotsFrom = (double*)defitem->ScriptVar(NAME_Slots, nullptr);
|
||||||
static_cast<AHexenArmor*>(item)->Slots[2] = static_cast<AHexenArmor*>(defitem)->Slots[2];
|
memcpy(SlotsTo, SlotsFrom, 4 * sizeof(double));
|
||||||
static_cast<AHexenArmor*>(item)->Slots[3] = static_cast<AHexenArmor*>(defitem)->Slots[3];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((dmflags & DF_COOP_LOSE_POWERUPS) &&
|
else if ((dmflags & DF_COOP_LOSE_POWERUPS) &&
|
||||||
|
@ -1364,12 +1363,15 @@ void APlayerPawn::GiveDefaultInventory ()
|
||||||
// it provides player class based protection that should not affect
|
// it provides player class based protection that should not affect
|
||||||
// any other protection item.
|
// any other protection item.
|
||||||
PClassPlayerPawn *myclass = GetClass();
|
PClassPlayerPawn *myclass = GetClass();
|
||||||
GiveInventoryType(RUNTIME_CLASS(AHexenArmor));
|
GiveInventoryType(PClass::FindActor(NAME_HexenArmor));
|
||||||
AHexenArmor *harmor = FindInventory<AHexenArmor>();
|
auto harmor = FindInventory(NAME_HexenArmor);
|
||||||
harmor->Slots[4] = myclass->HexenArmor[0];
|
|
||||||
|
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||||
|
double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr);
|
||||||
|
Slots[4] = myclass->HexenArmor[0];
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
harmor->SlotsIncrement[i] = myclass->HexenArmor[i + 1];
|
SlotsIncrement[i] = myclass->HexenArmor[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// BasicArmor must come right after that. It should not affect any
|
// BasicArmor must come right after that. It should not affect any
|
||||||
|
|
|
@ -452,16 +452,165 @@ class BasicArmorPickup : Armor
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
class HexenArmor : Armor native
|
class HexenArmor : Armor
|
||||||
{
|
{
|
||||||
|
|
||||||
native double Slots[5];
|
double Slots[5];
|
||||||
native double SlotsIncrement[4];
|
double SlotsIncrement[4];
|
||||||
|
|
||||||
Default
|
Default
|
||||||
{
|
{
|
||||||
+Inventory.KEEPDEPLETED
|
+Inventory.KEEPDEPLETED
|
||||||
+Inventory.UNTOSSABLE
|
+Inventory.UNTOSSABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// AHexenArmor :: CreateCopy
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override Inventory CreateCopy (Actor 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).
|
||||||
|
let copy = HexenArmor(Spawn("HexenArmor"));
|
||||||
|
copy.AddArmorToSlot (health, Amount);
|
||||||
|
GoAwayAndDie ();
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// AHexenArmor :: CreateTossable
|
||||||
|
//
|
||||||
|
// Since this isn't really a single item, you can't drop it. Ever.
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override Inventory CreateTossable ()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// AHexenArmor :: HandlePickup
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override bool HandlePickup (Inventory item)
|
||||||
|
{
|
||||||
|
if (item is "HexenArmor")
|
||||||
|
{
|
||||||
|
if (AddArmorToSlot (item.health, item.Amount))
|
||||||
|
{
|
||||||
|
item.bPickupGood = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// AHexenArmor :: AddArmorToSlot
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
protected bool AddArmorToSlot (int slot, int amount)
|
||||||
|
{
|
||||||
|
double hits;
|
||||||
|
|
||||||
|
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;
|
||||||
|
let total = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
|
||||||
|
let 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
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override void AbsorbDamage (int damage, Name damageType, out 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// AHexenArmor :: DepleteOrDestroy
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
override void DepleteOrDestroy()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
Slots[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,32 @@ class Inventory : Actor native
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// AInventory :: DepleteOrDestroy
|
||||||
|
//
|
||||||
|
// If the item is depleted, just change its amount to 0, otherwise it's destroyed.
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
virtual void DepleteOrDestroy ()
|
||||||
|
{
|
||||||
|
// If it's not ammo or an internal armor, destroy it.
|
||||||
|
// Ammo needs to stick around, even when it's zero for the benefit
|
||||||
|
// of the weapons that use it and to maintain the maximum ammo
|
||||||
|
// amounts a backpack might have given.
|
||||||
|
// Armor shouldn't be removed because they only work properly when
|
||||||
|
// they are the last items in the inventory.
|
||||||
|
if (bKeepDepleted)
|
||||||
|
{
|
||||||
|
Amount = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// AInventory :: Travelled
|
// AInventory :: Travelled
|
||||||
|
|
Loading…
Reference in a new issue