diff --git a/Source/Entities/AHuman.cpp b/Source/Entities/AHuman.cpp index 79cae5588b..f84fecb1bb 100644 --- a/Source/Entities/AHuman.cpp +++ b/Source/Entities/AHuman.cpp @@ -648,9 +648,9 @@ bool AHuman::EquipFirearm(bool doEquip) { // Found proper device to equip, so make the switch! if (pWeapon && pWeapon->IsWeapon()) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -658,6 +658,13 @@ bool AHuman::EquipFirearm(bool doEquip) { AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order, so rotate to the device in question. + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + m_Inventory.pop_front(); + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pWeapon); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -694,9 +701,9 @@ bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) { // Found proper device to equip, so make the switch! if (pDevice && pDevice->IsInGroup(group)) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -713,6 +720,13 @@ bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) { } } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + m_Inventory.pop_front(); + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pDevice); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -749,9 +763,9 @@ bool AHuman::EquipLoadedFirearmInGroup(std::string group, std::string excludeGro // Found proper device to equip, so make the switch! if (pFirearm && !pFirearm->NeedsReloading() && pFirearm->IsInGroup(group) && !pFirearm->IsInGroup(excludeGroup)) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -759,6 +773,14 @@ bool AHuman::EquipLoadedFirearmInGroup(std::string group, std::string excludeGro AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); + m_Inventory.pop_front(); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + m_Inventory.pop_front(); + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pFirearm); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -796,9 +818,9 @@ bool AHuman::EquipNamedDevice(const std::string& moduleName, const std::string& // Found proper device to equip, so make the switch! if (pDevice && (moduleName.empty() || pDevice->GetModuleName() == moduleName) && pDevice->GetPresetName() == presetName) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -806,6 +828,13 @@ bool AHuman::EquipNamedDevice(const std::string& moduleName, const std::string& AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order, so rotate to the device in question. + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); + + // Erase the inventory entry containing the device. + *m_Inventory.begin() = 0; + m_Inventory.pop_front(); + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pDevice); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -844,9 +873,9 @@ bool AHuman::EquipThrowable(bool doEquip) { if (pThrown) // && pThrown->IsWeapon()) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -854,6 +883,13 @@ bool AHuman::EquipThrowable(bool doEquip) { AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + m_Inventory.pop_front(); + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pThrown); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -968,9 +1004,9 @@ bool AHuman::EquipShield() { HeldDevice* pShield = dynamic_cast(*itr); // Found proper device to equip, so make the switch! if (pShield && pShield->IsShield()) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -978,6 +1014,13 @@ bool AHuman::EquipShield() { AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + m_Inventory.pop_front(); + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pShield); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -1027,9 +1070,9 @@ bool AHuman::EquipShieldInBGArm(bool depositToFront) { HeldDevice* pShield = dynamic_cast(*itr); // Found proper device to equip, so make the switch! if (pShield && (pShield->IsShield() || pShield->IsDualWieldable())) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pBGArm->GetHeldDevice()) { @@ -1041,6 +1084,13 @@ bool AHuman::EquipShieldInBGArm(bool depositToFront) { } } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + m_Inventory.pop_front(); + // Now put the device we were looking for and found into the hand m_pBGArm->SetHeldDevice(pShield); // Move the hand to a poisition so it looks like the new device was drawn from inventory