Skip to content

Commit 07bb70b

Browse files
authored
Merge pull request #222 from Architector4/patch-2
Preserve inventory order when AI switches weapons
2 parents 01fb6b0 + 3147f7d commit 07bb70b

File tree

1 file changed

+71
-21
lines changed

1 file changed

+71
-21
lines changed

Source/Entities/AHuman.cpp

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -648,16 +648,23 @@ bool AHuman::EquipFirearm(bool doEquip) {
648648
// Found proper device to equip, so make the switch!
649649
if (pWeapon && pWeapon->IsWeapon()) {
650650
if (doEquip) {
651-
// Erase the inventory entry containing the device we now have switched to
652-
*itr = 0;
653-
m_Inventory.erase(itr);
651+
// The next code may cause reallocation, so we can't just use the same pointer.
652+
// Store how far into the inventory the device is, memory wise.
653+
size_t device_offset = itr - m_Inventory.begin();
654654

655655
// Put back into the inventory what we had in our hands, if anything
656656
if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) {
657657
heldDevice->Deactivate();
658658
AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice));
659659
}
660660

661+
// We want to preserve inventory order, so rotate to the device in question.
662+
std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end());
663+
664+
// Erase the inventory entry containing the device we now have switched to
665+
*m_Inventory.begin() = 0;
666+
m_Inventory.pop_front();
667+
661668
// Now put the device we were looking for and found into the hand
662669
m_pFGArm->SetHeldDevice(pWeapon);
663670
// 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) {
694701
// Found proper device to equip, so make the switch!
695702
if (pDevice && pDevice->IsInGroup(group)) {
696703
if (doEquip) {
697-
// Erase the inventory entry containing the device we now have switched to
698-
*itr = 0;
699-
m_Inventory.erase(itr);
704+
// The next code may cause reallocation, so we can't just use the same pointer.
705+
// Store how far into the inventory the device is, memory wise.
706+
size_t device_offset = itr - m_Inventory.begin();
700707

701708
// Put back into the inventory what we had in our hands, if anything
702709
if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) {
@@ -713,6 +720,13 @@ bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) {
713720
}
714721
}
715722

723+
// We want to preserve inventory order, so rotate it to the device in question.
724+
std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end());
725+
726+
// Erase the inventory entry containing the device we now have switched to
727+
*m_Inventory.begin() = 0;
728+
m_Inventory.pop_front();
729+
716730
// Now put the device we were looking for and found into the hand
717731
m_pFGArm->SetHeldDevice(pDevice);
718732
// Move the hand to a poisition so it looks like the new device was drawn from inventory
@@ -749,16 +763,24 @@ bool AHuman::EquipLoadedFirearmInGroup(std::string group, std::string excludeGro
749763
// Found proper device to equip, so make the switch!
750764
if (pFirearm && !pFirearm->NeedsReloading() && pFirearm->IsInGroup(group) && !pFirearm->IsInGroup(excludeGroup)) {
751765
if (doEquip) {
752-
// Erase the inventory entry containing the device we now have switched to
753-
*itr = 0;
754-
m_Inventory.erase(itr);
766+
// The next code may cause reallocation, so we can't just use the same pointer.
767+
// Store how far into the inventory the device is, memory wise.
768+
size_t device_offset = itr - m_Inventory.begin();
755769

756770
// Put back into the inventory what we had in our hands, if anything
757771
if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) {
758772
m_pFGArm->GetHeldDevice()->Deactivate();
759773
AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice));
760774
}
761775

776+
// We want to preserve inventory order, so rotate it to the device in question.
777+
std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end());
778+
m_Inventory.pop_front();
779+
780+
// Erase the inventory entry containing the device we now have switched to
781+
*m_Inventory.begin() = 0;
782+
m_Inventory.pop_front();
783+
762784
// Now put the device we were looking for and found into the hand
763785
m_pFGArm->SetHeldDevice(pFirearm);
764786
// Move the hand to a poisition so it looks like the new device was drawn from inventory
@@ -796,16 +818,23 @@ bool AHuman::EquipNamedDevice(const std::string& moduleName, const std::string&
796818
// Found proper device to equip, so make the switch!
797819
if (pDevice && (moduleName.empty() || pDevice->GetModuleName() == moduleName) && pDevice->GetPresetName() == presetName) {
798820
if (doEquip) {
799-
// Erase the inventory entry containing the device we now have switched to
800-
*itr = 0;
801-
m_Inventory.erase(itr);
821+
// The next code may cause reallocation, so we can't just use the same pointer.
822+
// Store how far into the inventory the device is, memory wise.
823+
size_t device_offset = itr - m_Inventory.begin();
802824

803825
// Put back into the inventory what we had in our hands, if anything
804826
if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) {
805827
heldDevice->Deactivate();
806828
AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice));
807829
}
808830

831+
// We want to preserve inventory order, so rotate to the device in question.
832+
std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end());
833+
834+
// Erase the inventory entry containing the device.
835+
*m_Inventory.begin() = 0;
836+
m_Inventory.pop_front();
837+
809838
// Now put the device we were looking for and found into the hand
810839
m_pFGArm->SetHeldDevice(pDevice);
811840
// Move the hand to a poisition so it looks like the new device was drawn from inventory
@@ -844,16 +873,23 @@ bool AHuman::EquipThrowable(bool doEquip) {
844873
if (pThrown) // && pThrown->IsWeapon())
845874
{
846875
if (doEquip) {
847-
// Erase the inventory entry containing the device we now have switched to
848-
*itr = 0;
849-
m_Inventory.erase(itr);
876+
// The next code may cause reallocation, so we can't just use the same pointer.
877+
// Store how far into the inventory the device is, memory wise.
878+
size_t device_offset = itr - m_Inventory.begin();
850879

851880
// Put back into the inventory what we had in our hands, if anything
852881
if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) {
853882
heldDevice->Deactivate();
854883
AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice));
855884
}
856885

886+
// We want to preserve inventory order, so rotate it to the device in question.
887+
std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end());
888+
889+
// Erase the inventory entry containing the device we now have switched to
890+
*m_Inventory.begin() = 0;
891+
m_Inventory.pop_front();
892+
857893
// Now put the device we were looking for and found into the hand
858894
m_pFGArm->SetHeldDevice(pThrown);
859895
// Move the hand to a poisition so it looks like the new device was drawn from inventory
@@ -968,16 +1004,23 @@ bool AHuman::EquipShield() {
9681004
HeldDevice* pShield = dynamic_cast<HeldDevice*>(*itr);
9691005
// Found proper device to equip, so make the switch!
9701006
if (pShield && pShield->IsShield()) {
971-
// Erase the inventory entry containing the device we now have switched to
972-
*itr = 0;
973-
m_Inventory.erase(itr);
1007+
// The next code may cause reallocation, so we can't just use the same pointer.
1008+
// Store how far into the inventory the device is, memory wise.
1009+
size_t device_offset = itr - m_Inventory.begin();
9741010

9751011
// Put back into the inventory what we had in our hands, if anything
9761012
if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) {
9771013
heldDevice->Deactivate();
9781014
AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice));
9791015
}
9801016

1017+
// We want to preserve inventory order, so rotate it to the device in question.
1018+
std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end());
1019+
1020+
// Erase the inventory entry containing the device we now have switched to
1021+
*m_Inventory.begin() = 0;
1022+
m_Inventory.pop_front();
1023+
9811024
// Now put the device we were looking for and found into the hand
9821025
m_pFGArm->SetHeldDevice(pShield);
9831026
// 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) {
10271070
HeldDevice* pShield = dynamic_cast<HeldDevice*>(*itr);
10281071
// Found proper device to equip, so make the switch!
10291072
if (pShield && (pShield->IsShield() || pShield->IsDualWieldable())) {
1030-
// Erase the inventory entry containing the device we now have switched to
1031-
*itr = 0;
1032-
m_Inventory.erase(itr);
1073+
// The next code may cause reallocation, so we can't just use the same pointer.
1074+
// Store how far into the inventory the device is, memory wise.
1075+
size_t device_offset = itr - m_Inventory.begin();
10331076

10341077
// Put back into the inventory what we had in our hands, if anything
10351078
if (HeldDevice* heldDevice = m_pBGArm->GetHeldDevice()) {
@@ -1041,6 +1084,13 @@ bool AHuman::EquipShieldInBGArm(bool depositToFront) {
10411084
}
10421085
}
10431086

1087+
// We want to preserve inventory order, so rotate it to the device in question.
1088+
std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end());
1089+
1090+
// Erase the inventory entry containing the device we now have switched to
1091+
*m_Inventory.begin() = 0;
1092+
m_Inventory.pop_front();
1093+
10441094
// Now put the device we were looking for and found into the hand
10451095
m_pBGArm->SetHeldDevice(pShield);
10461096
// Move the hand to a poisition so it looks like the new device was drawn from inventory

0 commit comments

Comments
 (0)