- took the weapon selection logic out of the WeaponSlots data and blocked all direct access to the weapon slots internals

This seriously needs to be independent from the data store and better abstracted. More work to come to move this to its proper place.
This commit is contained in:
Christoph Oelckers 2018-11-24 22:03:56 +01:00
parent b6d0d5008e
commit 51ee623b3b
11 changed files with 286 additions and 278 deletions

View File

@ -233,7 +233,6 @@ void DBot::Dofire (ticcmd_t *cmd)
}
}
// prediction aiming
shootmissile:
Dist = player->mo->Distance2D(enemy);
fm = Dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed;
bglobal.SetBodyAt(enemy->Pos() + enemy->Vel.XY() * fm * 2, 1);

View File

@ -2631,7 +2631,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
int count = ReadByte(stream);
if (slot < NUM_WEAPON_SLOTS)
{
players[pnum].weapons.Slots[slot].Clear();
players[pnum].weapons.ClearSlot(slot);
}
for(i = 0; i < count; ++i)
{

View File

@ -275,6 +275,226 @@ 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)
@ -283,8 +503,8 @@ CCMD (slot)
if (slot < NUM_WEAPON_SLOTS)
{
SendItemUse = players[consoleplayer].weapons.Slots[slot].PickWeapon (&players[consoleplayer],
!(dmflags2 & DF2_DONTCHECKAMMO));
// Needs to be redone
SendItemUse = PickWeapon(&players[consoleplayer], slot, !(dmflags2 & DF2_DONTCHECKAMMO));
}
}
}
@ -316,7 +536,7 @@ CCMD (turn180)
CCMD (weapnext)
{
SendItemUse = players[consoleplayer].weapons.PickNextWeapon (&players[consoleplayer]);
SendItemUse = PickNextWeapon (&players[consoleplayer]);
// [BC] Option to display the name of the weapon being cycled to.
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
{
@ -331,7 +551,7 @@ CCMD (weapnext)
CCMD (weapprev)
{
SendItemUse = players[consoleplayer].weapons.PickPrevWeapon (&players[consoleplayer]);
SendItemUse = PickPrevWeapon (&players[consoleplayer]);
// [BC] Option to display the name of the weapon being cycled to.
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
{

View File

@ -200,26 +200,6 @@ bool AInventory::Grind(bool items)
return Super::Grind(items);
}
//===========================================================================
//
// AInventory :: Use
//
//===========================================================================
bool AInventory::CallUse(bool pickup)
{
IFVIRTUAL(AInventory, Use)
{
VMValue params[2] = { (DObject*)this, pickup };
int retval;
VMReturn ret(&retval);
VMCall(func, params, 2, &ret, 1);
return !!retval;
}
return false;
}
//===========================================================================
//
//
@ -304,25 +284,6 @@ PalEntry AInventory::CallGetBlend()
else return 0;
}
//===========================================================================
//
// AInventory :: PrevItem
//
// Returns the previous item.
//
//===========================================================================
AInventory *AInventory::PrevItem ()
{
AInventory *item = Owner->Inventory;
while (item != NULL && item->Inventory != this)
{
item = item->Inventory;
}
return item;
}
//===========================================================================
//
// AInventory :: PrevInv

View File

@ -81,13 +81,11 @@ public:
bool CallTryPickup(AActor *toucher, AActor **toucher_return = NULL); // Wrapper for script function.
void DepleteOrDestroy (); // virtual on the script side.
bool CallUse(bool pickup); // virtual on the script side.
PalEntry CallGetBlend(); // virtual on the script side.
bool GetNoTeleportFreeze(); // virtual on the script side.
bool DoRespawn();
AInventory *PrevItem(); // Returns the item preceding this one in the list.
AInventory *PrevInv(); // Returns the previous item with IF_INVBAR set.
AInventory *NextInv(); // Returns the next item with IF_INVBAR set.

View File

@ -317,73 +317,6 @@ int FWeaponSlot::LocateWeapon(PClassActor *type)
return -1;
}
//===========================================================================
//
// 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 *FWeaponSlot::PickWeapon(player_t *player, bool checkammo)
{
int i, j;
if (player->mo == nullptr)
{
return nullptr;
}
// Does this slot even have any weapons?
if (Weapons.Size() == 0)
{
return player->ReadyWeapon;
}
if (player->ReadyWeapon != nullptr)
{
for (i = 0; (unsigned)i < Weapons.Size(); i++)
{
if (Weapons[i].Type == player->ReadyWeapon->GetClass() ||
(player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP &&
player->ReadyWeapon->SisterWeapon != nullptr &&
player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i].Type))
{
for (j = (i == 0 ? Weapons.Size() - 1 : i - 1);
j != i;
j = (j == 0 ? Weapons.Size() - 1 : j - 1))
{
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[j].Type));
if (weap != nullptr && weap->IsKindOf(NAME_Weapon))
{
if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false))
{
return weap;
}
}
}
}
}
}
for (i = Weapons.Size() - 1; i >= 0; i--)
{
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[i].Type));
if (weap != nullptr && weap->IsKindOf(NAME_Weapon))
{
if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false))
{
return weap;
}
}
}
return player->ReadyWeapon;
}
//===========================================================================
//
// FWeaponSlot :: SetInitialPositions
@ -533,154 +466,6 @@ DEFINE_ACTION_FUNCTION(FWeaponSlots, LocateWeapon)
return MIN(numret, 3);
}
//===========================================================================
//
// 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 *FWeaponSlots::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 = Slots[startslot].Size() - 1;
}
slot = startslot;
index = startindex;
do
{
if (++index >= Slots[slot].Size())
{
index = 0;
slotschecked++;
if (++slot >= NUM_WEAPON_SLOTS)
{
slot = 0;
}
}
PClassActor *type = Slots[slot].GetWeapon(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 *FWeaponSlots::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 = Slots[slot].Size() - 1;
}
PClassActor *type = Slots[slot].GetWeapon(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 :: AddExtraWeapons
@ -976,10 +761,10 @@ CCMD (setslot)
}
else if (PlayingKeyConf != nullptr)
{
PlayingKeyConf->Slots[slot].Clear();
PlayingKeyConf->ClearSlot(slot);
for (int i = 2; i < argv.argc(); ++i)
{
PlayingKeyConf->Slots[slot].AddWeapon(argv[i]);
PlayingKeyConf->AddWeapon(slot, argv[i]);
}
}
else

View File

@ -15,7 +15,6 @@ public:
bool AddWeapon (const char *type);
bool AddWeapon (PClassActor *type);
void AddWeaponList (const char *list, bool clear);
AWeapon *PickWeapon (player_t *player, bool checkammo = false);
int Size () const { return (int)Weapons.Size(); }
int LocateWeapon (PClassActor *type);
@ -56,10 +55,9 @@ struct FWeaponSlots
FWeaponSlots() { Clear(); }
FWeaponSlots(const FWeaponSlots &other);
private:
FWeaponSlot Slots[NUM_WEAPON_SLOTS];
AWeapon *PickNextWeapon (player_t *player);
AWeapon *PickPrevWeapon (player_t *player);
public:
void Clear ();
bool LocateWeapon (PClassActor *type, int *const slot, int *const index);
@ -76,7 +74,49 @@ struct FWeaponSlots
void AddSlot(int slot, PClassActor *type, bool feedback);
void AddSlotDefault(int slot, PClassActor *type, bool feedback);
// Abstract access interface to the slots
void AddWeapon(int slot, PClassActor *type)
{
if (slot >= 0 && slot < NUM_WEAPON_SLOTS)
{
Slots[slot].AddWeapon(type);
}
}
void AddWeapon(int slot, const char *type)
{
if (slot >= 0 && slot < NUM_WEAPON_SLOTS)
{
Slots[slot].AddWeapon(type);
}
}
void ClearSlot(int slot)
{
if (slot >= 0 && slot < NUM_WEAPON_SLOTS)
{
Slots[slot].Weapons.Clear();
}
}
int SlotSize(int slot) const
{
if (slot >= 0 && slot < NUM_WEAPON_SLOTS)
{
return Slots[slot].Weapons.Size();
}
return 0;
}
PClassActor *GetWeapon(int slot, int index) const
{
if (slot >= 0 && slot < NUM_WEAPON_SLOTS && (unsigned)index < Slots[slot].Weapons.Size())
{
return Slots[slot].GetWeapon(index);
}
return nullptr;
}
};
void P_PlaybackKeyConfWeapons(FWeaponSlots *slots);

View File

@ -582,9 +582,9 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
else
{
// Order ammo by use of weapons in the weapon slots
for (k = 0; k < NUM_WEAPON_SLOTS; k++) for(j = 0; j < CPlayer->weapons.Slots[k].Size(); j++)
for (k = 0; k < NUM_WEAPON_SLOTS; k++) for(j = 0; j < CPlayer->weapons.SlotSize(k); j++)
{
PClassActor *weap = CPlayer->weapons.Slots[k].GetWeapon(j);
PClassActor *weap = CPlayer->weapons.GetWeapon(k, j);
if (weap)
{
@ -782,9 +782,9 @@ static void DrawWeapons(player_t *CPlayer, int x, int y)
}
// And now everything in the weapon slots back to front
for (k = NUM_WEAPON_SLOTS - 1; k >= 0; k--) for(j = CPlayer->weapons.Slots[k].Size() - 1; j >= 0; j--)
for (k = NUM_WEAPON_SLOTS - 1; k >= 0; k--) for(j = CPlayer->weapons.SlotSize(k) - 1; j >= 0; j--)
{
PClassActor *weap = CPlayer->weapons.Slots[k].GetWeapon(j);
PClassActor *weap = CPlayer->weapons.GetWeapon(k, j);
if (weap)
{
inv=CPlayer->mo->FindInventory(weap);

View File

@ -527,9 +527,9 @@ class CommandDrawSwitchableImage : public CommandDrawImage
if(condition == WEAPONSLOT) //weaponslots
{
drawAlt = 1; //draw off state until we know we have something.
for (int i = 0; i < statusBar->CPlayer->weapons.Slots[conditionalValue[0]].Size(); i++)
for (int i = 0; i < statusBar->CPlayer->weapons.SlotSize(conditionalValue[0]); i++)
{
PClassActor *weap = statusBar->CPlayer->weapons.Slots[conditionalValue[0]].GetWeapon(i);
PClassActor *weap = statusBar->CPlayer->weapons.GetWeapon(conditionalValue[0], i);
if(weap == NULL)
{
continue;

View File

@ -1126,9 +1126,14 @@ bool AActor::UseInventory (AInventory *item)
{
return false;
}
if (!item->CallUse (false))
IFVIRTUALPTR(item, AInventory, Use)
{
return false;
VMValue params[2] = { item, false };
int retval;
VMReturn ret(&retval);
VMCall(func, params, 2, &ret, 1);
if (!retval) return false;
}
if (dmflags2 & DF2_INFINITE_INVENTORY)

View File

@ -655,9 +655,9 @@ void player_t::SendPitchLimits() const
bool player_t::HasWeaponsInSlot(int slot) const
{
for (int i = 0; i < weapons.Slots[slot].Size(); i++)
for (int i = 0; i < weapons.SlotSize(slot); i++)
{
PClassActor *weap = weapons.Slots[slot].GetWeapon(i);
PClassActor *weap = weapons.GetWeapon(slot, i);
if (weap != NULL && mo->FindInventory(weap)) return true;
}
return false;