mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 06:53:58 +00:00
- moved the weapon selection logic to PlayerPawn as overridable virtual functions.
This commit is contained in:
parent
51ee623b3b
commit
f260709e73
5 changed files with 270 additions and 248 deletions
256
src/g_game.cpp
256
src/g_game.cpp
|
@ -275,236 +275,22 @@ CCMD (turnspeeds)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FWeaponSlot :: PickWeapon
|
||||
//
|
||||
// Picks a weapon from this slot. If no weapon is selected in this slot,
|
||||
// or the first weapon in this slot is selected, returns the last weapon.
|
||||
// Otherwise, returns the previous weapon in this slot. This means
|
||||
// precedence is given to the last weapon in the slot, which by convention
|
||||
// is probably the strongest. Does not return weapons you have no ammo
|
||||
// for or which you do not possess.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AWeapon *PickWeapon(player_t *player, int slot, bool checkammo)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (player->mo == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
int Size = player->weapons.SlotSize(slot);
|
||||
// Does this slot even have any weapons?
|
||||
if (Size == 0)
|
||||
{
|
||||
return player->ReadyWeapon;
|
||||
}
|
||||
if (player->ReadyWeapon != nullptr)
|
||||
{
|
||||
for (i = 0; (unsigned)i < Size; i++)
|
||||
{
|
||||
auto weapontype = player->weapons.GetWeapon(slot, i);
|
||||
if (weapontype == player->ReadyWeapon->GetClass() ||
|
||||
(player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP &&
|
||||
player->ReadyWeapon->SisterWeapon != nullptr &&
|
||||
player->ReadyWeapon->SisterWeapon->GetClass() == weapontype))
|
||||
{
|
||||
for (j = (i == 0 ? Size - 1 : i - 1);
|
||||
j != i;
|
||||
j = (j == 0 ? Size - 1 : j - 1))
|
||||
{
|
||||
auto weapontype2 = player->weapons.GetWeapon(slot, j);
|
||||
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(weapontype2));
|
||||
|
||||
if (weap != nullptr && weap->IsKindOf(NAME_Weapon))
|
||||
{
|
||||
if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false))
|
||||
{
|
||||
return weap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = Size - 1; i >= 0; i--)
|
||||
{
|
||||
auto weapontype = player->weapons.GetWeapon(slot, i);
|
||||
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(weapontype));
|
||||
|
||||
if (weap != nullptr && weap->IsKindOf(NAME_Weapon))
|
||||
{
|
||||
if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false))
|
||||
{
|
||||
return weap;
|
||||
}
|
||||
}
|
||||
}
|
||||
return player->ReadyWeapon;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FindMostRecentWeapon
|
||||
//
|
||||
// Locates the slot and index for the most recently selected weapon. If the
|
||||
// player is in the process of switching to a new weapon, that is the most
|
||||
// recently selected weapon. Otherwise, the current weapon is the most recent
|
||||
// weapon.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static bool FindMostRecentWeapon(player_t *player, int *slot, int *index)
|
||||
{
|
||||
if (player->PendingWeapon != WP_NOCHANGE)
|
||||
{
|
||||
return player->weapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index);
|
||||
}
|
||||
else if (player->ReadyWeapon != nullptr)
|
||||
{
|
||||
AWeapon *weap = player->ReadyWeapon;
|
||||
if (!player->weapons.LocateWeapon(weap->GetClass(), slot, index))
|
||||
{
|
||||
// If the current weapon wasn't found and is powered up,
|
||||
// look for its non-powered up version.
|
||||
if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != nullptr)
|
||||
{
|
||||
return player->weapons.LocateWeapon(weap->SisterWeaponType, slot, index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FWeaponSlots :: PickNextWeapon
|
||||
//
|
||||
// Returns the "next" weapon for this player. If the current weapon is not
|
||||
// in a slot, then it just returns that weapon, since there's nothing to
|
||||
// consider it relative to.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AWeapon *PickNextWeapon(player_t *player)
|
||||
{
|
||||
int startslot, startindex;
|
||||
int slotschecked = 0;
|
||||
|
||||
if (player->mo == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (player->ReadyWeapon == nullptr || FindMostRecentWeapon(player, &startslot, &startindex))
|
||||
{
|
||||
int slot;
|
||||
int index;
|
||||
|
||||
if (player->ReadyWeapon == nullptr)
|
||||
{
|
||||
startslot = NUM_WEAPON_SLOTS - 1;
|
||||
startindex = player->weapons.SlotSize(startslot) - 1;
|
||||
}
|
||||
|
||||
slot = startslot;
|
||||
index = startindex;
|
||||
do
|
||||
{
|
||||
if (++index >= player->weapons.SlotSize(slot))
|
||||
{
|
||||
index = 0;
|
||||
slotschecked++;
|
||||
if (++slot >= NUM_WEAPON_SLOTS)
|
||||
{
|
||||
slot = 0;
|
||||
}
|
||||
}
|
||||
PClassActor *type = player->weapons.GetWeapon(slot, index);
|
||||
AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type));
|
||||
if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false))
|
||||
{
|
||||
return weap;
|
||||
}
|
||||
} while ((slot != startslot || index != startindex) && slotschecked <= NUM_WEAPON_SLOTS);
|
||||
}
|
||||
return player->ReadyWeapon;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FWeaponSlots :: PickPrevWeapon
|
||||
//
|
||||
// Returns the "previous" weapon for this player. If the current weapon is
|
||||
// not in a slot, then it just returns that weapon, since there's nothing to
|
||||
// consider it relative to.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AWeapon *PickPrevWeapon(player_t *player)
|
||||
{
|
||||
int startslot, startindex;
|
||||
int slotschecked = 0;
|
||||
|
||||
if (player->mo == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (player->ReadyWeapon == nullptr || FindMostRecentWeapon(player, &startslot, &startindex))
|
||||
{
|
||||
int slot;
|
||||
int index;
|
||||
|
||||
if (player->ReadyWeapon == nullptr)
|
||||
{
|
||||
startslot = 0;
|
||||
startindex = 0;
|
||||
}
|
||||
|
||||
slot = startslot;
|
||||
index = startindex;
|
||||
do
|
||||
{
|
||||
if (--index < 0)
|
||||
{
|
||||
slotschecked++;
|
||||
if (--slot < 0)
|
||||
{
|
||||
slot = NUM_WEAPON_SLOTS - 1;
|
||||
}
|
||||
index = player->weapons.SlotSize(slot) - 1;
|
||||
}
|
||||
PClassActor *type = player->weapons.GetWeapon(slot, index);
|
||||
AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type));
|
||||
if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false))
|
||||
{
|
||||
return weap;
|
||||
}
|
||||
} while ((slot != startslot || index != startindex) && slotschecked <= NUM_WEAPON_SLOTS);
|
||||
}
|
||||
return player->ReadyWeapon;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CCMD (slot)
|
||||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
int slot = atoi (argv[1]);
|
||||
|
||||
if (slot < NUM_WEAPON_SLOTS)
|
||||
auto mo = players[consoleplayer].mo;
|
||||
if (slot < NUM_WEAPON_SLOTS && mo)
|
||||
{
|
||||
// Needs to be redone
|
||||
SendItemUse = PickWeapon(&players[consoleplayer], slot, !(dmflags2 & DF2_DONTCHECKAMMO));
|
||||
IFVIRTUALPTR(mo, APlayerPawn, PickWeapon)
|
||||
{
|
||||
VMValue param[] = { mo, slot, !(dmflags2 & DF2_DONTCHECKAMMO) };
|
||||
VMReturn ret((void**)&SendItemUse);
|
||||
VMCall(func, param, 3, &ret, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -536,7 +322,18 @@ CCMD (turn180)
|
|||
|
||||
CCMD (weapnext)
|
||||
{
|
||||
SendItemUse = PickNextWeapon (&players[consoleplayer]);
|
||||
auto mo = players[consoleplayer].mo;
|
||||
if (mo)
|
||||
{
|
||||
// Needs to be redone
|
||||
IFVIRTUALPTR(mo, APlayerPawn, PickNextWeapon)
|
||||
{
|
||||
VMValue param[] = { mo };
|
||||
VMReturn ret((void**)&SendItemUse);
|
||||
VMCall(func, param, 1, &ret, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// [BC] Option to display the name of the weapon being cycled to.
|
||||
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
|
||||
{
|
||||
|
@ -551,7 +348,18 @@ CCMD (weapnext)
|
|||
|
||||
CCMD (weapprev)
|
||||
{
|
||||
SendItemUse = PickPrevWeapon (&players[consoleplayer]);
|
||||
auto mo = players[consoleplayer].mo;
|
||||
if (mo)
|
||||
{
|
||||
// Needs to be redone
|
||||
IFVIRTUALPTR(mo, APlayerPawn, PickPrevWeapon)
|
||||
{
|
||||
VMValue param[] = { mo };
|
||||
VMReturn ret((void**)&SendItemUse);
|
||||
VMCall(func, param, 1, &ret, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// [BC] Option to display the name of the weapon being cycled to.
|
||||
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
|
||||
{
|
||||
|
|
|
@ -204,29 +204,6 @@ void AWeapon::MarkPrecacheSounds() const
|
|||
ReadySound.MarkUsed();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: CheckAmmo
|
||||
//
|
||||
// Returns true if there is enough ammo to shoot. If not, selects the
|
||||
// next weapon to use.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeapon::CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo, int ammocount)
|
||||
{
|
||||
IFVIRTUAL(AWeapon, CheckAmmo)
|
||||
{
|
||||
VMValue params[] = { (DObject*)this, fireMode, autoSwitch, requireAmmo, ammocount };
|
||||
VMReturn ret;
|
||||
int retval;
|
||||
ret.IntAt(&retval);
|
||||
VMCall(func, params, 5, &ret, 1);
|
||||
return !!retval;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Weapon slots ***********************************************************/
|
||||
|
||||
//===========================================================================
|
||||
|
@ -466,6 +443,23 @@ DEFINE_ACTION_FUNCTION(FWeaponSlots, LocateWeapon)
|
|||
return MIN(numret, 3);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FWeaponSlots, GetWeapon)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FWeaponSlots);
|
||||
PARAM_INT(slot);
|
||||
PARAM_INT(index);
|
||||
ACTION_RETURN_POINTER(self->GetWeapon(slot, index));
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FWeaponSlots, SlotSize)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FWeaponSlots);
|
||||
PARAM_INT(slot);
|
||||
ACTION_RETURN_INT(self->SlotSize(slot));
|
||||
return 1;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FWeaponSlots :: AddExtraWeapons
|
||||
|
|
|
@ -174,7 +174,6 @@ public:
|
|||
AltFire,
|
||||
EitherFire
|
||||
};
|
||||
bool CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo=false, int ammocount = -1);
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
|
@ -961,4 +961,6 @@ struct WeaponSlots native
|
|||
{
|
||||
native bool, int, int LocateWeapon(class<Weapon> weap);
|
||||
native static void SetupWeaponSlots(PlayerPawn pp);
|
||||
native class<Weapon> GetWeapon(int slot, int index);
|
||||
native int SlotSize(int slot);
|
||||
}
|
||||
|
|
|
@ -1721,6 +1721,225 @@ class PlayerPawn : Actor native
|
|||
return TeleportFreezeTime;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FWeaponSlot :: PickWeapon
|
||||
//
|
||||
// Picks a weapon from this slot. If no weapon is selected in this slot,
|
||||
// or the first weapon in this slot is selected, returns the last weapon.
|
||||
// Otherwise, returns the previous weapon in this slot. This means
|
||||
// precedence is given to the last weapon in the slot, which by convention
|
||||
// is probably the strongest. Does not return weapons you have no ammo
|
||||
// for or which you do not possess.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
virtual Weapon PickWeapon(int slot, bool checkammo)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
let player = self.player;
|
||||
int Size = player.weapons.SlotSize(slot);
|
||||
// Does this slot even have any weapons?
|
||||
if (Size == 0)
|
||||
{
|
||||
return player.ReadyWeapon;
|
||||
}
|
||||
let ReadyWeapon = player.ReadyWeapon;
|
||||
if (ReadyWeapon != null)
|
||||
{
|
||||
for (i = 0; i < Size; i++)
|
||||
{
|
||||
let weapontype = player.weapons.GetWeapon(slot, i);
|
||||
if (weapontype == ReadyWeapon.GetClass() ||
|
||||
(ReadyWeapon.bPOWERED_UP && ReadyWeapon.SisterWeapon != null && ReadyWeapon.SisterWeapon.GetClass() == weapontype))
|
||||
{
|
||||
for (j = (i == 0 ? Size - 1 : i - 1);
|
||||
j != i;
|
||||
j = (j == 0 ? Size - 1 : j - 1))
|
||||
{
|
||||
let weapontype2 = player.weapons.GetWeapon(slot, j);
|
||||
let weap = Weapon(player.mo.FindInventory(weapontype2));
|
||||
|
||||
if (weap != null)
|
||||
{
|
||||
if (!checkammo || weap.CheckAmmo(Weapon.EitherFire, false))
|
||||
{
|
||||
return weap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = Size - 1; i >= 0; i--)
|
||||
{
|
||||
let weapontype = player.weapons.GetWeapon(slot, i);
|
||||
let weap = Weapon(player.mo.FindInventory(weapontype));
|
||||
|
||||
if (weap != null)
|
||||
{
|
||||
if (!checkammo || weap.CheckAmmo(Weapon.EitherFire, false))
|
||||
{
|
||||
return weap;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ReadyWeapon;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FindMostRecentWeapon
|
||||
//
|
||||
// Locates the slot and index for the most recently selected weapon. If the
|
||||
// player is in the process of switching to a new weapon, that is the most
|
||||
// recently selected weapon. Otherwise, the current weapon is the most recent
|
||||
// weapon.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool, int, int FindMostRecentWeapon()
|
||||
{
|
||||
let player = self.player;
|
||||
let ReadyWeapon = player.ReadyWeapon;
|
||||
if (player.PendingWeapon != WP_NOCHANGE)
|
||||
{
|
||||
return player.weapons.LocateWeapon(player.PendingWeapon.GetClass());
|
||||
}
|
||||
else if (ReadyWeapon != null)
|
||||
{
|
||||
bool found;
|
||||
int slot;
|
||||
int index;
|
||||
[found, slot, index] = player.weapons.LocateWeapon(ReadyWeapon.GetClass());
|
||||
if (!found)
|
||||
{
|
||||
// If the current weapon wasn't found and is powered up,
|
||||
// look for its non-powered up version.
|
||||
if (ReadyWeapon.bPOWERED_UP && ReadyWeapon.SisterWeaponType != null)
|
||||
{
|
||||
return player.weapons.LocateWeapon(ReadyWeapon.SisterWeaponType);
|
||||
}
|
||||
return false, 0, 0;
|
||||
}
|
||||
return true, slot, index;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false, 0, 0;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FWeaponSlots :: PickNextWeapon
|
||||
//
|
||||
// Returns the "next" weapon for this player. If the current weapon is not
|
||||
// in a slot, then it just returns that weapon, since there's nothing to
|
||||
// consider it relative to.
|
||||
//
|
||||
//===========================================================================
|
||||
const NUM_WEAPON_SLOTS = 10;
|
||||
|
||||
virtual Weapon PickNextWeapon()
|
||||
{
|
||||
let player = self.player;
|
||||
bool found;
|
||||
int startslot, startindex;
|
||||
int slotschecked = 0;
|
||||
|
||||
[found, startslot, startindex] = FindMostRecentWeapon();
|
||||
let ReadyWeapon = player.ReadyWeapon;
|
||||
if (ReadyWeapon == null || found)
|
||||
{
|
||||
int slot;
|
||||
int index;
|
||||
|
||||
if (ReadyWeapon == null)
|
||||
{
|
||||
startslot = NUM_WEAPON_SLOTS - 1;
|
||||
startindex = player.weapons.SlotSize(startslot) - 1;
|
||||
}
|
||||
|
||||
slot = startslot;
|
||||
index = startindex;
|
||||
do
|
||||
{
|
||||
if (++index >= player.weapons.SlotSize(slot))
|
||||
{
|
||||
index = 0;
|
||||
slotschecked++;
|
||||
if (++slot >= NUM_WEAPON_SLOTS)
|
||||
{
|
||||
slot = 0;
|
||||
}
|
||||
}
|
||||
let type = player.weapons.GetWeapon(slot, index);
|
||||
let weap = Weapon(FindInventory(type));
|
||||
if (weap != null && weap.CheckAmmo(Weapon.EitherFire, false))
|
||||
{
|
||||
return weap;
|
||||
}
|
||||
} while ((slot != startslot || index != startindex) && slotschecked <= NUM_WEAPON_SLOTS);
|
||||
}
|
||||
return ReadyWeapon;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FWeaponSlots :: PickPrevWeapon
|
||||
//
|
||||
// Returns the "previous" weapon for this player. If the current weapon is
|
||||
// not in a slot, then it just returns that weapon, since there's nothing to
|
||||
// consider it relative to.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
virtual Weapon PickPrevWeapon()
|
||||
{
|
||||
let player = self.player;
|
||||
int startslot, startindex;
|
||||
bool found;
|
||||
int slotschecked = 0;
|
||||
|
||||
[found, startslot, startindex] = FindMostRecentWeapon();
|
||||
if (player.ReadyWeapon == null || found)
|
||||
{
|
||||
int slot;
|
||||
int index;
|
||||
|
||||
if (player.ReadyWeapon == null)
|
||||
{
|
||||
startslot = 0;
|
||||
startindex = 0;
|
||||
}
|
||||
|
||||
slot = startslot;
|
||||
index = startindex;
|
||||
do
|
||||
{
|
||||
if (--index < 0)
|
||||
{
|
||||
slotschecked++;
|
||||
if (--slot < 0)
|
||||
{
|
||||
slot = NUM_WEAPON_SLOTS - 1;
|
||||
}
|
||||
index = player.weapons.SlotSize(slot) - 1;
|
||||
}
|
||||
let type = player.weapons.GetWeapon(slot, index);
|
||||
let weap = Weapon(FindInventory(type));
|
||||
if (weap != null && weap.CheckAmmo(Weapon.EitherFire, false))
|
||||
{
|
||||
return weap;
|
||||
}
|
||||
} while ((slot != startslot || index != startindex) && slotschecked <= NUM_WEAPON_SLOTS);
|
||||
}
|
||||
return player.ReadyWeapon;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue