From 51ee623b3bdb9eb6bd7ff3fc7ef9a93891e766c0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 24 Nov 2018 22:03:56 +0100 Subject: [PATCH] - 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. --- src/b_func.cpp | 1 - src/d_net.cpp | 2 +- src/g_game.cpp | 228 +++++++++++++++++++++++++- src/g_inventory/a_pickups.cpp | 39 ----- src/g_inventory/a_pickups.h | 2 - src/g_inventory/a_weapons.cpp | 219 +------------------------ src/g_inventory/a_weapons.h | 48 +++++- src/g_shared/shared_hud.cpp | 8 +- src/g_statusbar/sbarinfo_commands.cpp | 4 +- src/p_mobj.cpp | 9 +- src/p_user.cpp | 4 +- 11 files changed, 286 insertions(+), 278 deletions(-) diff --git a/src/b_func.cpp b/src/b_func.cpp index 6f8191b95..87eaa66b6 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -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); diff --git a/src/d_net.cpp b/src/d_net.cpp index 37969fa1d..4c86a664d 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -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) { diff --git a/src/g_game.cpp b/src/g_game.cpp index 27aff3abf..94b9b5a2a 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -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 (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 (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(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(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) { diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 33c33413d..ac9cbe330 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -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 diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 97f94bff0..3815c6f77 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -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. diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 6408c90c4..60fb582b9 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -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 (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 (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(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(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 diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index fcc3b1134..1c4109425 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -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); diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index a3b7c2a6d..88fc1ecbf 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -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); diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index 5a6da4b31..a4249e832 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -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; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 7788c9ca9..a82342d5f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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) diff --git a/src/p_user.cpp b/src/p_user.cpp index a35c66dac..e75865fcd 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -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;