mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 07:11:54 +00:00
342 lines
9.8 KiB
Text
342 lines
9.8 KiB
Text
/*
|
|
** a_ammo.cpp
|
|
** Implements ammo and backpack items.
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright 2000-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 Ammo : Inventory
|
|
{
|
|
int BackpackAmount;
|
|
int BackpackMaxAmount;
|
|
/*meta*/ int DropAmount;
|
|
|
|
property BackpackAmount: BackpackAmount;
|
|
property BackpackMaxAmount: BackpackMaxAmount;
|
|
property DropAmount: DropAmount;
|
|
|
|
Default
|
|
{
|
|
+INVENTORY.KEEPDEPLETED
|
|
Inventory.PickupSound "misc/ammo_pkup";
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// AAmmo :: GetParentAmmo
|
|
//
|
|
// Returns the least-derived ammo type that this ammo is a descendant of.
|
|
// That is, if this ammo is an immediate subclass of Ammo, then this ammo's
|
|
// type is returned. If this ammo's superclass is not Ammo, then this
|
|
// function travels up the inheritance chain until it finds a type that is
|
|
// an immediate subclass of Ammo and returns that.
|
|
//
|
|
// The intent of this is that all unique ammo types will be immediate
|
|
// subclasses of Ammo. To make different pickups with different ammo amounts,
|
|
// you subclass the type of ammo you want a different amount for and edit
|
|
// that.
|
|
//
|
|
//===========================================================================
|
|
|
|
Class<Ammo> GetParentAmmo ()
|
|
{
|
|
class<Object> type = GetClass();
|
|
|
|
while (type.GetParentClass() != "Ammo" && type.GetParentClass() != NULL)
|
|
{
|
|
type = type.GetParentClass();
|
|
}
|
|
return (class<Ammo>)(type);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// AAmmo :: HandlePickup
|
|
//
|
|
//===========================================================================
|
|
|
|
override bool HandlePickup (Inventory item)
|
|
{
|
|
let ammoitem = Ammo(item);
|
|
if (ammoitem != null && ammoitem.GetParentAmmo() == GetClass())
|
|
{
|
|
if (Amount < MaxAmount || sv_unlimited_pickup)
|
|
{
|
|
int receiving = item.Amount;
|
|
|
|
if (!item.bIgnoreSkill)
|
|
{ // extra ammo in baby mode and nightmare mode
|
|
receiving = int(receiving * G_SkillPropertyFloat(SKILLP_AmmoFactor));
|
|
}
|
|
int oldamount = Amount;
|
|
|
|
if (Amount > 0 && Amount + receiving < 0)
|
|
{
|
|
Amount = 0x7fffffff;
|
|
}
|
|
else
|
|
{
|
|
Amount += receiving;
|
|
}
|
|
if (Amount > MaxAmount && !sv_unlimited_pickup)
|
|
{
|
|
Amount = MaxAmount;
|
|
}
|
|
item.bPickupGood = true;
|
|
|
|
// If the player previously had this ammo but ran out, possibly switch
|
|
// to a weapon that uses it, but only if the player doesn't already
|
|
// have a weapon pending.
|
|
|
|
if (oldamount == 0 && Owner != null && Owner.player != null)
|
|
{
|
|
PlayerPawn(Owner).CheckWeaponSwitch(GetClass());
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// AAmmo :: CreateCopy
|
|
//
|
|
//===========================================================================
|
|
|
|
override Inventory CreateCopy (Actor other)
|
|
{
|
|
Inventory copy;
|
|
int amount = Amount;
|
|
|
|
// extra ammo in baby mode and nightmare mode
|
|
if (!bIgnoreSkill)
|
|
{
|
|
amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor));
|
|
}
|
|
|
|
let type = GetParentAmmo();
|
|
if (GetClass() != type && type != null)
|
|
{
|
|
if (!GoAway ())
|
|
{
|
|
Destroy ();
|
|
}
|
|
|
|
copy = Inventory(Spawn (type));
|
|
copy.Amount = amount;
|
|
copy.BecomeItem ();
|
|
}
|
|
else
|
|
{
|
|
copy = Super.CreateCopy (other);
|
|
copy.Amount = amount;
|
|
}
|
|
if (copy.Amount > copy.MaxAmount)
|
|
{ // Don't pick up more ammo than you're supposed to be able to carry.
|
|
copy.Amount = copy.MaxAmount;
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// AAmmo :: CreateTossable
|
|
//
|
|
//===========================================================================
|
|
|
|
override Inventory CreateTossable()
|
|
{
|
|
Inventory copy = Super.CreateTossable();
|
|
if (copy != null)
|
|
{ // Do not increase ammo by dropping it and picking it back up at
|
|
// certain skill levels.
|
|
copy.bIgnoreSkill = true;
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
class BackpackItem : Inventory
|
|
{
|
|
bool bDepleted;
|
|
|
|
//===========================================================================
|
|
//
|
|
// ABackpackItem :: CreateCopy
|
|
//
|
|
// A backpack is being added to a player who doesn't yet have one. Give them
|
|
// every kind of ammo, and increase their max amounts.
|
|
//
|
|
//===========================================================================
|
|
|
|
override Inventory CreateCopy (Actor other)
|
|
{
|
|
// Find every unique type of ammoitem. Give it to the player if
|
|
// he doesn't have it already, and double its maximum capacity.
|
|
uint end = AllActorClasses.Size();
|
|
for (uint i = 0; i < end; ++i)
|
|
{
|
|
let type = AllActorClasses[i];
|
|
|
|
if (type.GetParentClass() == 'Ammo')
|
|
{
|
|
let ammotype = (class<Ammo>)(type);
|
|
let ammoitem = Ammo(other.FindInventory(ammotype));
|
|
int amount = GetDefaultByType(ammotype).BackpackAmount;
|
|
// extra ammo in baby mode and nightmare mode
|
|
if (!bIgnoreSkill)
|
|
{
|
|
amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor));
|
|
}
|
|
if (amount < 0) amount = 0;
|
|
if (ammoitem == NULL)
|
|
{ // The player did not have the ammoitem. Add it.
|
|
ammoitem = Ammo(Spawn(ammotype));
|
|
ammoitem.Amount = bDepleted ? 0 : amount;
|
|
if (ammoitem.BackpackMaxAmount > ammoitem.MaxAmount)
|
|
{
|
|
ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
|
|
}
|
|
if (ammoitem.Amount > ammoitem.MaxAmount)
|
|
{
|
|
ammoitem.Amount = ammoitem.MaxAmount;
|
|
}
|
|
ammoitem.AttachToOwner (other);
|
|
}
|
|
else
|
|
{ // The player had the ammoitem. Give some more.
|
|
if (ammoitem.MaxAmount < ammoitem.BackpackMaxAmount)
|
|
{
|
|
ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
|
|
}
|
|
if (!bDepleted && ammoitem.Amount < ammoitem.MaxAmount)
|
|
{
|
|
ammoitem.Amount += amount;
|
|
if (ammoitem.Amount > ammoitem.MaxAmount)
|
|
{
|
|
ammoitem.Amount = ammoitem.MaxAmount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Super.CreateCopy (other);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// ABackpackItem :: HandlePickup
|
|
//
|
|
// When the player picks up another backpack, just give them more ammoitem.
|
|
//
|
|
//===========================================================================
|
|
|
|
override bool HandlePickup (Inventory item)
|
|
{
|
|
// Since you already have a backpack, that means you already have every
|
|
// kind of ammo in your inventory, so we don't need to look at the
|
|
// entire PClass list to discover what kinds of ammo exist, and we don't
|
|
// have to alter the MaxAmount either.
|
|
if (item is 'BackpackItem')
|
|
{
|
|
for (let probe = Owner.Inv; probe != NULL; probe = probe.Inv)
|
|
{
|
|
if (probe.GetParentClass() == 'Ammo')
|
|
{
|
|
if (probe.Amount < probe.MaxAmount || sv_unlimited_pickup)
|
|
{
|
|
int amount = Ammo(probe).Default.BackpackAmount;
|
|
// extra ammo in baby mode and nightmare mode
|
|
if (!bIgnoreSkill)
|
|
{
|
|
amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor));
|
|
}
|
|
probe.Amount += amount;
|
|
if (probe.Amount > probe.MaxAmount && !sv_unlimited_pickup)
|
|
{
|
|
probe.Amount = probe.MaxAmount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// The pickup always succeeds, even if you didn't get anything
|
|
item.bPickupGood = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// ABackpackItem :: CreateTossable
|
|
//
|
|
// The tossed backpack must not give out any more ammo, otherwise a player
|
|
// could cheat by dropping their backpack and picking it up for more ammoitem.
|
|
//
|
|
//===========================================================================
|
|
|
|
override Inventory CreateTossable ()
|
|
{
|
|
let pack = BackpackItem(Super.CreateTossable());
|
|
if (pack != NULL)
|
|
{
|
|
pack.bDepleted = true;
|
|
}
|
|
return pack;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// ABackpackItem :: DetachFromOwner
|
|
//
|
|
//===========================================================================
|
|
|
|
override void DetachFromOwner ()
|
|
{
|
|
// When removing a backpack, drop the player's ammo maximums to normal
|
|
|
|
for (let item = Owner.Inv; item != NULL; item = item.Inv)
|
|
{
|
|
if (item is 'Ammo' && item.MaxAmount == Ammo(item).BackpackMaxAmount)
|
|
{
|
|
item.MaxAmount = item.Default.MaxAmount;
|
|
if (item.Amount > item.MaxAmount)
|
|
{
|
|
item.Amount = item.MaxAmount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|