diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 5efe7da7a..4cd3327cb 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,11 @@ +December 25, 2006 (Changes by Graf Zahl) +- Converted the Communicator to DECORATE. +- Renamed the new armor properties to use the same names as Skulltag to avoid + confusion. They still don't need a separate base class as in Skulltag though. +- Added Skulltag-type armor bonus that increases the max amount that can be given + by other armor items. +- Separated all armor related code from a_pickups.cpp into a_armor.cpp. + December 24, 2006 (Changes by Graf Zahl) - Replaced several calls to S_GetSoundPlayingInfo with S_IsActorPlayingSomething because S_GetSoundPlayingInfo cannot properly resolve player and random sounds. diff --git a/src/actor.h b/src/actor.h index 057a53adc..10a679482 100644 --- a/src/actor.h +++ b/src/actor.h @@ -550,6 +550,7 @@ public: // Finds the first item of a particular type. AInventory *FindInventory (const PClass *type) const; + AInventory *FindInventory (FName type) const; template T *FindInventory () const { return static_cast (FindInventory (RUNTIME_CLASS(T))); diff --git a/src/g_game.cpp b/src/g_game.cpp index ef4c4af75..b9bf6d01b 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -417,9 +417,8 @@ CCMD (useflechette) for (j = 0; j < 3; ++j) { - const PClass *type = PClass::FindClass (bagnames[(i+j)%3]); AInventory *item; - if (type != NULL && (item = who->FindInventory (type))) + if (item = who->FindInventory (bagnames[(i+j)%3])) { SendItemUse = item; break; diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp new file mode 100644 index 000000000..9c4da7362 --- /dev/null +++ b/src/g_shared/a_armor.cpp @@ -0,0 +1,486 @@ +#include + +#include "info.h" +#include "gi.h" +#include "r_data.h" +#include "a_pickups.h" +#include "templates.h" + + +IMPLEMENT_STATELESS_ACTOR (AArmor, Any, -1, 0) + PROP_Inventory_PickupSound ("misc/armor_pkup") +END_DEFAULTS + +IMPLEMENT_STATELESS_ACTOR (ABasicArmor, Any, -1, 0) +END_DEFAULTS + +IMPLEMENT_STATELESS_ACTOR (ABasicArmorPickup, Any, -1, 0) + PROP_Inventory_MaxAmount (0) + PROP_Inventory_FlagsSet (IF_AUTOACTIVATE) +END_DEFAULTS + +IMPLEMENT_STATELESS_ACTOR (ABasicArmorBonus, Any, -1, 0) + PROP_Inventory_MaxAmount (0) + PROP_Inventory_FlagsSet (IF_AUTOACTIVATE|IF_ALWAYSPICKUP) + PROP_BasicArmorBonus_SavePercent (FRACUNIT/3) +END_DEFAULTS + +IMPLEMENT_STATELESS_ACTOR (AHexenArmor, Any, -1, 0) + PROP_Inventory_FlagsSet (IF_UNDROPPABLE) +END_DEFAULTS + + +//=========================================================================== +// +// ABasicArmor :: Serialize +// +//=========================================================================== + +void ABasicArmor::Serialize (FArchive &arc) +{ + Super::Serialize (arc); + arc << SavePercent << BonusCount; +} + +//=========================================================================== +// +// 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 (); + if (Icon == 0) + { + switch (gameinfo.gametype) + { + case GAME_Doom: + Icon = TexMan.CheckForTexture (SavePercent == FRACUNIT/3 ? "ARM1A0" : "ARM2A0", FTexture::TEX_Any); + break; + + case GAME_Heretic: + Icon = TexMan.CheckForTexture (SavePercent == FRACUNIT/2 ? "SHLDA0" : "SHD2A0", FTexture::TEX_Any); + break; + + case GAME_Strife: + Icon = TexMan.CheckForTexture (SavePercent == FRACUNIT/3 ? "I_ARM2" : "I_ARM1", FTexture::TEX_Any); + break; + + default: + break; + } + } +} + +//=========================================================================== +// +// 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 (0, 0, 0, NO_REPLACE); + copy->SavePercent = SavePercent != 0 ? SavePercent : FRACUNIT/3; + copy->Amount = Amount; + copy->MaxAmount = MaxAmount; + copy->Icon = Icon; + copy->BonusCount = BonusCount; + GoAwayAndDie (); + return copy; +} + +//=========================================================================== +// +// ABasicArmor :: HandlePickup +// +//=========================================================================== + +bool ABasicArmor::HandlePickup (AInventory *item) +{ + if (item->GetClass() == RUNTIME_CLASS(ABasicArmor)) + { + // You shouldn't be picking up BasicArmor anyway. + return true; + } + if (Inventory != NULL) + { + return Inventory->HandlePickup (item); + } + return false; +} + +//=========================================================================== +// +// ABasicArmor :: AbsorbDamage +// +//=========================================================================== + +void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) +{ + if (damageType != NAME_Water) + { + int saved = FixedMul (damage, SavePercent); + if (Amount < saved) + { + saved = Amount; + } + newdamage -= saved; + Amount -= saved; + if (Amount == 0) + { + // The armor has become useless + SavePercent = 0; + // Now see if the player has some more armor in their inventory + // and use it if so. As in Strife, the best armor is used up first. + ABasicArmorPickup *best = NULL; + AInventory *probe = Owner->Inventory; + while (probe != NULL) + { + if (probe->IsKindOf (RUNTIME_CLASS(ABasicArmorPickup))) + { + ABasicArmorPickup *inInv = static_cast(probe); + if (best == NULL || best->SavePercent < inInv->SavePercent) + { + best = inInv; + } + } + probe = probe->Inventory; + } + if (best != NULL) + { + Owner->UseInventory (best); + } + } + } + if (Inventory != NULL) + { + Inventory->AbsorbDamage (damage, damageType, newdamage); + } +} + +//=========================================================================== +// +// ABasicArmorPickup :: Serialize +// +//=========================================================================== + +void ABasicArmorPickup::Serialize (FArchive &arc) +{ + Super::Serialize (arc); + arc << SavePercent << SaveAmount; + arc << DropTime; +} + +//=========================================================================== +// +// ABasicArmorPickup :: CreateCopy +// +//=========================================================================== + +AInventory *ABasicArmorPickup::CreateCopy (AActor *other) +{ + ABasicArmorPickup *copy = static_cast (Super::CreateCopy (other)); + copy->SavePercent = SavePercent; + copy->SaveAmount = SaveAmount; + 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 (); + + if (armor == NULL) + { + armor = Spawn (0,0,0, NO_REPLACE); + 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; + return true; +} + +//=========================================================================== +// +// ABasicArmorBonus :: Serialize +// +//=========================================================================== + +void ABasicArmorBonus::Serialize (FArchive &arc) +{ + Super::Serialize (arc); + arc << SavePercent << SaveAmount << MaxSaveAmount << BonusCount << BonusMax; +} + +//=========================================================================== +// +// ABasicArmorBonus :: CreateCopy +// +//=========================================================================== + +AInventory *ABasicArmorBonus::CreateCopy (AActor *other) +{ + ABasicArmorBonus *copy = static_cast (Super::CreateCopy (other)); + copy->SavePercent = SavePercent; + copy->SaveAmount = SaveAmount; + copy->MaxSaveAmount = MaxSaveAmount; + copy->BonusCount = BonusCount; + copy->BonusMax = BonusMax; + return copy; +} + +//=========================================================================== +// +// ABasicArmorBonus :: Use +// +// Tries to add to the amount of BasicArmor a player has. +// +//=========================================================================== + +bool ABasicArmorBonus::Use (bool pickup) +{ + ABasicArmor *armor = Owner->FindInventory (); + bool result = false; + + if (armor == NULL) + { + armor = Spawn (0,0,0, NO_REPLACE); + armor->BecomeItem (); + armor->Amount = 0; + armor->MaxAmount = MaxSaveAmount; + Owner->AddInventory (armor); + } + + if (BonusCount > 0 && armor->BonusCount < BonusMax) + { + armor->BonusCount = MIN (armor->BonusCount + BonusCount, BonusMax); + result = true; + } + + int saveAmount = MIN (SaveAmount, MaxSaveAmount); + + if (saveAmount <= 0) + { // If it can't give you anything, it's as good as used. + return BonusCount > 0 ? result : true; + } + + // If you already have more armor than this item can give you, you can't + // use it. + if (armor->Amount >= MaxSaveAmount + armor->BonusCount) + { + return result; + } + + if (armor->Amount <= 0) + { // Should never be less than 0, but might as well check anyway + armor->Amount = 0; + armor->Icon = Icon; + armor->SavePercent = SavePercent; + } + + armor->Amount = MIN(armor->Amount + saveAmount, MaxSaveAmount + armor->BonusCount); + armor->MaxAmount = MAX (armor->MaxAmount, MaxSaveAmount); + return true; +} + +//=========================================================================== +// +// AHexenArmor :: Serialize +// +//=========================================================================== + +void AHexenArmor::Serialize (FArchive &arc) +{ + Super::Serialize (arc); + arc << Slots[0] << Slots[1] << Slots[2] << Slots[3] + << Slots[4] + << SlotsIncrement[0] << SlotsIncrement[1] << SlotsIncrement[2] + << SlotsIncrement[3]; +} + +//=========================================================================== +// +// 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 (0, 0, 0, NO_REPLACE); + 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; + } + else if (Inventory != NULL) + { + return Inventory->HandlePickup (item); + } + return false; +} + +//=========================================================================== +// +// AHexenArmor :: AddArmorToSlot +// +//=========================================================================== + +bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount) +{ + APlayerPawn *ppawn; + int hits; + + if (actor->player != NULL) + { + ppawn = static_cast(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 * FRACUNIT; + fixed_t 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; + if (total < max) + { + Slots[slot] += hits; + return true; + } + } + return false; +} + +//=========================================================================== +// +// AHexenArmor :: AbsorbDamage +// +//=========================================================================== + +void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) +{ + if (damageType != NAME_Water) + { + fixed_t savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4]; + + if (savedPercent) + { // armor absorbed some damage + if (savedPercent > 100*FRACUNIT) + { + savedPercent = 100*FRACUNIT; + } + 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] -= Scale (damage, SlotsIncrement[i], 300); + if (Slots[i] < 2*FRACUNIT) + { + Slots[i] = 0; + } + } + else + { + Slots[i] = 0; + } + } + } + int saved = Scale (damage, savedPercent, 100*FRACUNIT); + if (saved > savedPercent >> (FRACBITS-1)) + { + saved = savedPercent >> (FRACBITS-1); + } + newdamage -= saved; + } + } + if (Inventory != NULL) + { + Inventory->AbsorbDamage (damage, damageType, newdamage); + } +} + diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 8fdcad772..af21e706a 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -165,8 +165,6 @@ AInventory *AAmmo::CreateCopy (AActor *other) return copy; } -/* Keys *******************************************************************/ - //--------------------------------------------------------------------------- // // FUNC P_GiveBody @@ -1270,472 +1268,6 @@ bool ACustomInventory::TryPickup (AActor *toucher) return useok; } -IMPLEMENT_STATELESS_ACTOR (AArmor, Any, -1, 0) - PROP_Inventory_PickupSound ("misc/armor_pkup") -END_DEFAULTS - -IMPLEMENT_STATELESS_ACTOR (ABasicArmor, Any, -1, 0) - PROP_SpawnState (S_HELD) -END_DEFAULTS - -IMPLEMENT_STATELESS_ACTOR (ABasicArmorPickup, Any, -1, 0) - PROP_Inventory_MaxAmount (0) - PROP_Inventory_FlagsSet (IF_AUTOACTIVATE) -END_DEFAULTS - -IMPLEMENT_STATELESS_ACTOR (ABasicArmorBonus, Any, -1, 0) - PROP_Inventory_MaxAmount (0) - PROP_Inventory_FlagsSet (IF_AUTOACTIVATE|IF_ALWAYSPICKUP) - PROP_BasicArmorBonus_SavePercent (FRACUNIT/3) -END_DEFAULTS - -IMPLEMENT_STATELESS_ACTOR (AHexenArmor, Any, -1, 0) - PROP_Inventory_FlagsSet (IF_UNDROPPABLE) -END_DEFAULTS - - -//=========================================================================== -// -// ABasicArmorPickup :: Serialize -// -//=========================================================================== - -void ABasicArmorPickup::Serialize (FArchive &arc) -{ - Super::Serialize (arc); - arc << SavePercent << SaveAmount; - arc << DropTime; -} - -//=========================================================================== -// -// ABasicArmorPickup :: CreateCopy -// -//=========================================================================== - -AInventory *ABasicArmorPickup::CreateCopy (AActor *other) -{ - ABasicArmorPickup *copy = static_cast (Super::CreateCopy (other)); - copy->SavePercent = SavePercent; - copy->SaveAmount = SaveAmount; - 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 (); - - if (armor == NULL) - { - armor = Spawn (0,0,0, NO_REPLACE); - armor->BecomeItem (); - armor->SavePercent = SavePercent; - armor->Amount = armor->MaxAmount = SaveAmount; - armor->Icon = Icon; - Owner->AddInventory (armor); - return true; - } - // If you already have more armor than this item gives you, you can't - // use it. - if (armor->Amount >= SaveAmount) - { - 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 = armor->MaxAmount = SaveAmount; - armor->Icon = Icon; - return true; -} - -//=========================================================================== -// -// ABasicArmorBonus :: Serialize -// -//=========================================================================== - -void ABasicArmorBonus::Serialize (FArchive &arc) -{ - Super::Serialize (arc); - arc << SavePercent << SaveAmount << MaxSaveAmount; -} - -//=========================================================================== -// -// ABasicArmorBonus :: CreateCopy -// -//=========================================================================== - -AInventory *ABasicArmorBonus::CreateCopy (AActor *other) -{ - ABasicArmorBonus *copy = static_cast (Super::CreateCopy (other)); - copy->SavePercent = SavePercent; - copy->SaveAmount = SaveAmount; - copy->MaxSaveAmount = MaxSaveAmount; - return copy; -} - -//=========================================================================== -// -// ABasicArmorBonus :: Use -// -// Tries to add to the amount of BasicArmor a player has. -// -//=========================================================================== - -bool ABasicArmorBonus::Use (bool pickup) -{ - ABasicArmor *armor = Owner->FindInventory (); - int saveAmount = MIN (SaveAmount, MaxSaveAmount); - - if (saveAmount <= 0) - { // If it can't give you anything, it's as good as used. - return true; - } - if (armor == NULL) - { - armor = Spawn (0,0,0, NO_REPLACE); - armor->BecomeItem (); - armor->SavePercent = SavePercent; - armor->Amount = saveAmount; - armor->MaxAmount = MaxSaveAmount; - armor->Icon = Icon; - Owner->AddInventory (armor); - return true; - } - // If you already have more armor than this item can give you, you can't - // use it. - if (armor->Amount >= MaxSaveAmount) - { - return false; - } - if (armor->Amount <= 0) - { // Should never be less than 0, but might as well check anyway - armor->Amount = 0; - armor->Icon = Icon; - armor->SavePercent = SavePercent; - } - armor->Amount += saveAmount; - armor->MaxAmount = MAX (armor->MaxAmount, MaxSaveAmount); - return true; -} - -//=========================================================================== -// -// ABasicArmor :: Serialize -// -//=========================================================================== - -void ABasicArmor::Serialize (FArchive &arc) -{ - Super::Serialize (arc); - arc << SavePercent; -} - -//=========================================================================== -// -// 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 (); - if (Icon == 0) - { - switch (gameinfo.gametype) - { - case GAME_Doom: - Icon = TexMan.CheckForTexture (SavePercent == FRACUNIT/3 ? "ARM1A0" : "ARM2A0", FTexture::TEX_Any); - break; - - case GAME_Heretic: - Icon = TexMan.CheckForTexture (SavePercent == FRACUNIT/2 ? "SHLDA0" : "SHD2A0", FTexture::TEX_Any); - break; - - case GAME_Strife: - Icon = TexMan.CheckForTexture (SavePercent == FRACUNIT/3 ? "I_ARM2" : "I_ARM1", FTexture::TEX_Any); - break; - - default: - break; - } - } -} - -//=========================================================================== -// -// 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 (0, 0, 0, NO_REPLACE); - copy->SavePercent = SavePercent != 0 ? SavePercent : FRACUNIT/3; - copy->Amount = Amount; - copy->MaxAmount = MaxAmount; - copy->Icon = Icon; - GoAwayAndDie (); - return copy; -} - -//=========================================================================== -// -// ABasicArmor :: HandlePickup -// -//=========================================================================== - -bool ABasicArmor::HandlePickup (AInventory *item) -{ - if (item->GetClass() == RUNTIME_CLASS(ABasicArmor)) - { - // You shouldn't be picking up BasicArmor anyway. - return true; - } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } - return false; -} - -//=========================================================================== -// -// ABasicArmor :: AbsorbDamage -// -//=========================================================================== - -void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) -{ - if (damageType != NAME_Water) - { - int saved = FixedMul (damage, SavePercent); - if (Amount < saved) - { - saved = Amount; - } - newdamage -= saved; - Amount -= saved; - if (Amount == 0) - { - // The armor has become useless - SavePercent = 0; - // Now see if the player has some more armor in their inventory - // and use it if so. As in Strife, the best armor is used up first. - ABasicArmorPickup *best = NULL; - AInventory *probe = Owner->Inventory; - while (probe != NULL) - { - if (probe->IsKindOf (RUNTIME_CLASS(ABasicArmorPickup))) - { - ABasicArmorPickup *inInv = static_cast(probe); - if (best == NULL || best->SavePercent < inInv->SavePercent) - { - best = inInv; - } - } - probe = probe->Inventory; - } - if (best != NULL) - { - Owner->UseInventory (best); - } - } - } - if (Inventory != NULL) - { - Inventory->AbsorbDamage (damage, damageType, newdamage); - } -} - -//=========================================================================== -// -// AHexenArmor :: Serialize -// -//=========================================================================== - -void AHexenArmor::Serialize (FArchive &arc) -{ - Super::Serialize (arc); - arc << Slots[0] << Slots[1] << Slots[2] << Slots[3] - << Slots[4] - << SlotsIncrement[0] << SlotsIncrement[1] << SlotsIncrement[2] - << SlotsIncrement[3]; -} - -//=========================================================================== -// -// 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 (0, 0, 0, NO_REPLACE); - 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; - } - else if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } - return false; -} - -//=========================================================================== -// -// AHexenArmor :: AddArmorToSlot -// -//=========================================================================== - -bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount) -{ - APlayerPawn *ppawn; - int hits; - - if (actor->player != NULL) - { - ppawn = static_cast(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 * FRACUNIT; - fixed_t 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; - if (total < max) - { - Slots[slot] += hits; - return true; - } - } - return false; -} - -//=========================================================================== -// -// AHexenArmor :: AbsorbDamage -// -//=========================================================================== - -void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) -{ - if (damageType != NAME_Water) - { - fixed_t savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4]; - - if (savedPercent) - { // armor absorbed some damage - if (savedPercent > 100*FRACUNIT) - { - savedPercent = 100*FRACUNIT; - } - 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] -= Scale (damage, SlotsIncrement[i], 300); - if (Slots[i] < 2*FRACUNIT) - { - Slots[i] = 0; - } - } - else - { - Slots[i] = 0; - } - } - } - int saved = Scale (damage, savedPercent, 100*FRACUNIT); - if (saved > savedPercent >> (FRACBITS-1)) - { - saved = savedPercent >> (FRACBITS-1); - } - newdamage -= saved; - } - } - if (Inventory != NULL) - { - Inventory->AbsorbDamage (damage, damageType, newdamage); - } -} - IMPLEMENT_STATELESS_ACTOR (AHealth, Any, -1, 0) PROP_Inventory_Amount (1) PROP_Inventory_MaxAmount (0) @@ -2086,20 +1618,3 @@ bool AMapRevealer::TryPickup (AActor *toucher) return true; } -FState ACommunicator::States[] = -{ - S_NORMAL (COMM, 'A', -1, NULL, NULL) -}; - -IMPLEMENT_ACTOR (ACommunicator, Strife, 206, 0) - PROP_Flags (MF_SPECIAL|MF_NOTDMATCH) - PROP_SpawnState (0) - PROP_StrifeType (176) - PROP_StrifeTeaserType (168) - PROP_StrifeTeaserType2 (172) - PROP_Inventory_Icon ("I_COMM") - PROP_Tag ("Communicator") - PROP_Inventory_PickupSound ("misc/p_pkup") - PROP_Inventory_PickupMessage("$TXT_COMMUNICATOR") -END_DEFAULTS - diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index e9e695baa..b989461a7 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -320,6 +320,7 @@ public: virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); fixed_t SavePercent; + int BonusCount; }; // BasicArmorPickup replaces the armor you have. @@ -347,6 +348,8 @@ public: fixed_t SavePercent; // The default, for when you don't already have armor int MaxSaveAmount; int SaveAmount; + int BonusCount; + int BonusMax; }; // Hexen armor consists of four separate armor types plus a conceptual armor @@ -404,11 +407,4 @@ public: bool bDepleted; }; -// When the communicator is in a player's inventory, the -// SendToCommunicator special can work. -class ACommunicator : public AInventory -{ - DECLARE_ACTOR (ACommunicator, AInventory) -}; - #endif //__A_PICKUPS_H__ diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index e136eefb9..bb556194a 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -672,7 +672,7 @@ private: DrINumber2 (i, left+268*xscale, top+76*yscale, 7*xscale, imgFONY0); // Does the player have a communicator? - item = CPlayer->mo->FindInventory (RUNTIME_CLASS(ACommunicator)); + item = CPlayer->mo->FindInventory (NAME_Communicator); if (item != NULL) { screen->DrawTexture (TexMan(item->Icon), @@ -730,7 +730,7 @@ private: }; for (i = 0; i < 6; ++i) { - item = CPlayer->mo->FindInventory (PClass::FindClass (WeaponList[i].TypeName)); + item = CPlayer->mo->FindInventory (WeaponList[i].TypeName); if (item != NULL) { diff --git a/src/namedef.h b/src/namedef.h index a08a6781c..7b4c1f9ac 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -217,3 +217,4 @@ xx(MomZ) xx(MapSpot) xx(PatrolPoint) xx(PatrolSpecial) +xx(Communicator) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 157f8363b..9edff9f76 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2557,9 +2557,9 @@ FUNC(LS_SendToCommunicator) if (arg1 && backSide) return false; - if (it != NULL && it->player != NULL && it->FindInventory()) + if (it != NULL && it->player != NULL && it->FindInventory(NAME_Communicator)) { - char name[32]; + char name[32]; sprintf (name, "svox/voc%d", arg0); if (!arg3) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 7304203c4..9feb4535c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -795,6 +795,11 @@ AInventory *AActor::FindInventory (const PClass *type) const return item; } +AInventory *AActor::FindInventory (FName type) const +{ + return FindInventory(PClass::FindClass(type)); +} + //============================================================================ // // AActor :: GiveInventoryType diff --git a/src/p_user.cpp b/src/p_user.cpp index dc0c86363..c1b98a1ff 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2035,7 +2035,7 @@ void P_PlayerThink (player_t *player) } else if (cmd->ucmd.upmove > 0 && !(player->cheats & CF_PREDICTING)) { - AInventory *fly = player->mo->FindInventory (PClass::FindClass (NAME_ArtiFly)); + AInventory *fly = player->mo->FindInventory (NAME_ArtiFly); if (fly != NULL) { player->mo->UseInventory (fly); diff --git a/src/thingdef.cpp b/src/thingdef.cpp index da1cd764b..7b9060dc3 100644 --- a/src/thingdef.cpp +++ b/src/thingdef.cpp @@ -3347,7 +3347,25 @@ static void AmmoDropAmount (AAmmo *defaults, Baggage &bag) static void ArmorMaxSaveAmount (ABasicArmorBonus *defaults, Baggage &bag) { SC_MustGetNumber(); - defaults->MaxSaveAmount=sc_Number; + defaults->MaxSaveAmount = sc_Number; +} + +//========================================================================== +// +//========================================================================== +static void ArmorMaxBonus (ABasicArmorBonus *defaults, Baggage &bag) +{ + SC_MustGetNumber(); + defaults->BonusCount = sc_Number; +} + +//========================================================================== +// +//========================================================================== +static void ArmorMaxBonusMax (ABasicArmorBonus *defaults, Baggage &bag) +{ + SC_MustGetNumber(); + defaults->BonusMax = sc_Number; } //========================================================================== @@ -4025,6 +4043,8 @@ static const ActorProps props[] = { "ammo.backpackmaxamount", (apf)AmmoBackpackMaxAmount, RUNTIME_CLASS(AAmmo) }, { "ammo.dropamount", (apf)AmmoDropAmount, RUNTIME_CLASS(AAmmo) }, { "args", ActorArgs, RUNTIME_CLASS(AActor) }, + { "armor.maxbonus", (apf)ArmorMaxBonus, RUNTIME_CLASS(ABasicArmorBonus) }, + { "armor.maxbonusmax", (apf)ArmorMaxBonusMax, RUNTIME_CLASS(ABasicArmorBonus) }, { "armor.maxsaveamount", (apf)ArmorMaxSaveAmount, RUNTIME_CLASS(ABasicArmorBonus) }, { "armor.saveamount", (apf)ArmorSaveAmount, RUNTIME_CLASS(AActor) }, { "armor.savepercent", (apf)ArmorSavePercent, RUNTIME_CLASS(AActor) }, diff --git a/src/thingdef_codeptr.cpp b/src/thingdef_codeptr.cpp index 789d2ce44..546f1d8ca 100644 --- a/src/thingdef_codeptr.cpp +++ b/src/thingdef_codeptr.cpp @@ -1260,23 +1260,19 @@ void DoTakeInventory(AActor * self, AActor * receiver) ENamedName item =(ENamedName)StateParameters[index]; int amount=EvalExpressionI (StateParameters[index+1], self); - const PClass * mi=PClass::FindClass(item); - if (pStateCall != NULL) pStateCall->Result=false; - if (mi) - { - AInventory * inv = receiver->FindInventory(mi); - if (inv && !inv->IsKindOf(RUNTIME_CLASS(AHexenArmor))) + AInventory * inv = receiver->FindInventory(item); + + if (inv && !inv->IsKindOf(RUNTIME_CLASS(AHexenArmor))) + { + if (inv->Amount > 0 && pStateCall != NULL) pStateCall->Result=true; + if (!amount || amount>=inv->Amount) { - if (inv->Amount > 0 && pStateCall != NULL) pStateCall->Result=true; - if (!amount || amount>=inv->Amount) - { - if (inv->IsKindOf(RUNTIME_CLASS(AAmmo))) inv->Amount=0; - else inv->Destroy(); - } - else inv->Amount-=amount; + if (inv->IsKindOf(RUNTIME_CLASS(AAmmo))) inv->Amount=0; + else inv->Destroy(); } + else inv->Amount-=amount; } } @@ -1579,8 +1575,7 @@ void A_SelectWeapon(AActor * actor) int index=CheckIndex(1, NULL); if (index<0 || actor->player == NULL) return; - const PClass * weapon= PClass::FindClass((ENamedName)StateParameters[index]); - AWeapon * weaponitem = static_cast(actor->FindInventory(weapon)); + AWeapon * weaponitem = static_cast(actor->FindInventory((ENamedName)StateParameters[index])); if (weaponitem != NULL && weaponitem->IsKindOf(RUNTIME_CLASS(AWeapon))) { @@ -1802,14 +1797,11 @@ void A_DropInventory(AActor * self) { int index=CheckIndex(1, &CallingState); if (index<0) return; - const PClass * ti = PClass::FindClass((ENamedName)StateParameters[index]); - if (ti) + + AInventory * inv = self->FindInventory((ENamedName)StateParameters[index]); + if (inv) { - AInventory * inv = self->FindInventory(ti); - if (inv) - { - self->DropInventory(inv); - } + self->DropInventory(inv); } } diff --git a/wadsrc/decorate/strife/strifeitems.txt b/wadsrc/decorate/strife/strifeitems.txt index 464a60b86..50df056dd 100644 --- a/wadsrc/decorate/strife/strifeitems.txt +++ b/wadsrc/decorate/strife/strifeitems.txt @@ -352,3 +352,22 @@ ACTOR Targeter : PowerupGiver 207 } } +// Communicator ----------------------------------------------------------------- + +ACTOR Communicator : Inventory 206 +{ + Game Strife + ConversationID 176, 168, 172 + +NOTDMATCH + Tag "Communicator" + Inventory.Icon "I_COMM" + Inventory.PickupSound "misc/p_pkup" + Inventory.PickupMessage "$TXT_COMMUNICATOR" + States + { + Spawn: + COMM A -1 + Stop + } +} + diff --git a/zdoom.vcproj b/zdoom.vcproj index 967735069..a7c0a9ec0 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - @@ -2725,6 +2717,14 @@ GeneratePreprocessedFile="0" /> + + + @@ -2747,7 +2747,7 @@ /> - - - @@ -4814,6 +4804,16 @@ Outputs="$(IntDir)/$(InputName).obj" /> + + + @@ -4838,16 +4838,6 @@ Outputs="$(IntDir)/$(InputName).obj" /> - - - @@ -4858,6 +4848,16 @@ Outputs="$(IntDir)/$(InputName).obj" /> + + + @@ -4882,16 +4882,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -4902,6 +4892,16 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + @@ -4926,16 +4926,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -4946,6 +4936,16 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + @@ -4970,16 +4970,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -4990,6 +4980,16 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + @@ -5069,7 +5069,7 @@ /> - - - @@ -5416,6 +5408,14 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + + + @@ -5481,7 +5485,7 @@ /> + + + @@ -5638,14 +5650,6 @@ GeneratePreprocessedFile="0" /> - - - @@ -5667,7 +5671,7 @@ /> + + @@ -5875,7 +5883,7 @@ /> - - - - - - - - - - - - - - @@ -8359,7 +8331,7 @@ /> - - - @@ -9192,6 +9156,14 @@ AdditionalIncludeDirectories="src\win32;$(NoInherit)" /> + + + @@ -9366,7 +9338,7 @@ />