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;