Fixes (by The_Bob):

- Fixed random freeze on win8/10
- Fixed crash on mercs entering sector
- Fixed crash when using cover display (del/end)
- Fixed attachment popup showing incompatible attachments (crash/freeze/confusion on clicking the option)
- Fixed attachment popup positioning
- Fixed LBE contents corruption/deletion
- Fixed access violation (out of array bounds) in interrupt code
- Fixed a bunch of random old stuff
- Got the project to build on VS2015
- Improved popup class handling of grayed out options
- Improved performance of get item assignment check (added by Flugente)
- Added Ctrl+Space bind for testing/fixing broken LBE contents


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8399 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
silversurfer
2017-04-12 08:09:12 +00:00
parent 5d02ca8894
commit fef0722178
22 changed files with 303 additions and 110 deletions
+1 -1
View File
@@ -433,7 +433,7 @@ void RemoveCoverObjectsFromViewArea()
INT8& bOverlayType = gCoverViewArea[ubX][ubY][ubZ].bOverlayType;
if ( bOverlayType != INVALID_COVER )
if ( bOverlayType != INVALID_COVER && sGridNo != -1 )
{
TileDefines tile = GetOverlayIndex( bOverlayType );
RemoveCoverObjectFromWorld( sGridNo, tile, (BOOLEAN) ubZ );
+1 -1
View File
@@ -1275,7 +1275,7 @@ INT8 GetDynamicOpinionDay( UINT8 usProfileA, UINT8 usProfileB, UINT8 usDay )
{
INT32 opinion = 0;
if ( usProfileA == NO_PROFILE || usProfileA == NO_PROFILE )
if ( usProfileA == NO_PROFILE || usProfileB == NO_PROFILE )
return opinion;
// only for today (0) or one of the last 3 days (1-3)
+43 -39
View File
@@ -675,30 +675,22 @@ void popupCallbackItem(INT16 itemId){
//UpdateAttachmentTooltips(gpItemDescObject, gubItemDescStatusIndex);
return;
}
/*
for(UINT16 i = 0; i < pInventoryPoolList.size(); i++){
if( pInventoryPoolList[i].object.usItem == itemId ) {
gpItemPointer = &pInventoryPoolList[i].object; // pick up the object (or stack)
DoAttachment((UINT8)gubPopupStatusIndex, guiPopupItemPos); // try to attach it
gpItemPointer = NULL; // and drop it
gItemDescAttachmentPopups[giActiveAttachmentPopup]->hide();
RenderItemDescriptionBox();
giActiveAttachmentPopup = -1;
//UpdateAttachmentTooltips(gpItemDescObject, gubItemDescStatusIndex);
return;
}
}
*/
}
bool popupCallbackItemInSector(INT16 itemId){
for(UINT16 i = 0; i < pInventoryPoolList.size(); i++)
if( pInventoryPoolList[i].object.usItem == itemId ) return true;
bool popupCallbackItemInSector(INT16 usAttachment, OBJECTTYPE * pObj, POPUP_OPTION * o){
for (UINT16 i = 0; i < pInventoryPoolList.size(); i++) {
if (pInventoryPoolList[i].object.usItem == usAttachment) {
if (ValidItemAttachmentSlot(pObj, usAttachment, true, false, 0, -1, true, NULL, GetItemSlots(pObj))) {
return true;
}
else {
o->color_shade = COLOR_RED;
return false;
}
}
}
//return ValidAttachment(itemId, pObj);
o->color_shade = COLOR_DKGREY;
return false;
}
@@ -2504,11 +2496,11 @@ void PocketPopupDefault( SOLDIERTYPE *pSoldier, INT16 sPocket ){
if( LBEPocketPopup.find(pocketType) == LBEPocketPopup.end() ){
// default for LBE slots - grenades + ammo for merc's guns
addAmmoToPocketPopup( pSoldier, sPocket, popup );
addAmmoToPocketPopup( pSoldier, sPocket, popup );
POPUP * subPopup = popup->addSubMenuOption( new std::wstring( BobbyRFilter[28]/*Grenades*/ ) );
popup->getSubPopupOption( popup->subPopupOptionCount-1 )->setPopupPosition( 10,10,POPUP_POSITION_RELATIVE );
addGrenadesToPocketPopup( pSoldier, sPocket, subPopup );
POPUP * subPopup = popup->addSubMenuOption( new std::wstring( BobbyRFilter[28]/*Grenades*/ ) );
popup->getSubPopupOption( popup->subPopupOptionCount-1 )->setPopupPosition( 10,10,POPUP_POSITION_RELATIVE );
addGrenadesToPocketPopup( pSoldier, sPocket, subPopup );
} else {
// popup definition for this slot exists - apply it to the popup
gsPocketUnderCursor = sPocket;
@@ -5885,16 +5877,24 @@ void UpdateAttachmentTooltips(OBJECTTYPE *pObject, UINT8 ubStatusIndex)
POPUP_OPTION * o = new POPUP_OPTION( &std::wstring( Item[ usAttachment ].szItemName ),
new popupCallbackFunction<void,UINT16>(&popupCallbackItem,usAttachment));
// set an availiability callback to gray out any compatible attachments not found in this sector
o->setAvail( new popupCallbackFunction<bool,UINT16>(&popupCallbackItemInSector,usAttachment) );
o->setAvail( new popupCallbackFunction3<bool,UINT16, OBJECTTYPE*, POPUP_OPTION*>(&popupCallbackItemInSector,usAttachment, pObject, o) );
if (loop == 11 && attachList.size() > 11){ // if there's too much stuff to list, we create a subpopup for the rest
gItemDescAttachmentPopups[slotCount]->addSubMenuOption( &std::wstring(L"More...") );
POPUP_SUB_POPUP_OPTION * tmp = gItemDescAttachmentPopups[slotCount]->getSubPopupOption(0);
// positioning sub popups is handled through the option that holds them
tmp->setPopupPosition( (gsInvDescX + gItemDescAttachmentsXY[slotCount].sX),
(gsInvDescY + gItemDescAttachmentsXY[slotCount].sY) + 32 ,
POPUP_POSITION_TOP_RIGHT); // put it to the right of the main box
if (gItemDescAttachmentPopups[slotCount]->Position.iX + 200 > SCREEN_WIDTH) {
// near screen edge, put it below the original box
tmp->setPopupPosition(
gItemDescAttachmentPopups[slotCount]->Position.iX,
gItemDescAttachmentPopups[slotCount]->Position.iY + gItemDescAttachmentPopups[slotCount]->getCurrentHeight(),
POPUP_POSITION_TOP_LEFT
);
}
else { // we still got room, position the next box to the right of the previous one
tmp->setPopupPosition(10,0,POPUP_POSITION_RELATIVE);
}
// hide the other box too
// note that we're working with the sub popup options's sub-popup here, not the option itself
@@ -6392,9 +6392,10 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason )
{
LBENODE* pLBE = gpItemDescObject->GetLBEPointer(gubItemDescStatusIndex);
// we have an item in this pocket
if( pLBE->inv[(AttachmentSlots[usAttachmentSlotIndexVector[slotCount]].ubPocketMapping -1)].exists() )
if (pLBE && pLBE->inv[(AttachmentSlots[usAttachmentSlotIndexVector[slotCount]].ubPocketMapping - 1)].exists()) {
// place item on the ground
AutoPlaceObjectToWorld(gpItemDescSoldier, &pLBE->inv[(AttachmentSlots[usAttachmentSlotIndexVector[slotCount]].ubPocketMapping -1)], TRUE);
AutoPlaceObjectToWorld(gpItemDescSoldier, &pLBE->inv[(AttachmentSlots[usAttachmentSlotIndexVector[slotCount]].ubPocketMapping - 1)], TRUE);
}
}
else // the soldier is wearing the LBE
{
@@ -6696,12 +6697,16 @@ INT8 DetermineShowLBE( )
}
else
{
if(gpItemDescObject->IsActiveLBE(gubItemDescStatusIndex))
return (gpItemDescObject->GetLBEPointer(gubItemDescStatusIndex)->lbeClass - 1);
else if(Item[gpItemDescObject->usItem].usItemClass == IC_LBEGEAR)
if (gpItemDescObject->IsActiveLBE(gubItemDescStatusIndex)) {
LBENODE* pLBE = gpItemDescObject->GetLBEPointer(gubItemDescStatusIndex);
return pLBE ? (pLBE->lbeClass - 1) : -1;
}
else if (Item[gpItemDescObject->usItem].usItemClass == IC_LBEGEAR) {
return (LoadBearingEquipment[Item[gpItemDescObject->usItem].ubClassIndex].lbeClass - 1);
else
}
else {
return -1;
}
}
}
}
@@ -8049,9 +8054,8 @@ void RenderLBENODEItems( OBJECTTYPE *pObj, int subObject )
}
LBENODE* pLBE = NULL;
if(activeNode == true)
{
pLBE = pObj->GetLBEPointer(subObject);
if(activeNode == true && ( pLBE = pObj->GetLBEPointer(subObject) ) != NULL )
{
lClass = pLBE->lbeClass;
}
else {
+2 -1
View File
@@ -4154,7 +4154,8 @@ BOOLEAN ChangeDropPackStatus(SOLDIERTYPE *pSoldier, BOOLEAN newStatus)
break;
}
if(gWorldItems[wi].object.IsActiveLBE(x)) {
if(gWorldItems[wi].object.GetLBEPointer(x)->lbeIndex != NONE) {
LBENODE* pLBE = gWorldItems[wi].object.GetLBEPointer(x);
if(pLBE && pLBE->lbeIndex != NONE) {
// Found an associated backpack so figure out how far that pack is from us
iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, gWorldItems[wi].sGridNo );
if(gWorldItems[wi].sGridNo == pSoldier->sGridNo) // standing on pack - pickup regardless
+109 -7
View File
@@ -6,6 +6,9 @@
#include "screenids.h"
#include "Action Items.h" // added by Flugente for the ACTION_ITEM_BLOW_UP value
#include "Random.h" // added by Flugente
#include "Message.h" // added by BOB for missing LBE info messages
#include "overhead.h" // added by BOB for missing LBE info messages
#include "Map Screen Interface.h" // added by BOB for missing LBE info messages
int BODYPOSFINAL = GUNSLINGPOCKPOS;//RESET in initInventory
@@ -24,6 +27,83 @@ extern UINT32 guiCurrentItemDescriptionScreen;
extern BOOLEAN fShowMapInventoryPool;
//extern BOOLEAN AutoPlaceObjectInInventoryStash( OBJECTTYPE *pItemPtr, INT32 sGridNo );
bool checkObjectLBEIntegrity(OBJECTTYPE * object) {
bool integrityCheck = TRUE;
for (int i = 0; i < object->ubNumberOfObjects; i++)
{
if ((*object)[i]->data.lbe.bLBE == -1 && object->GetLBEPointer(i) == NULL) {
integrityCheck = false;
}
}
return integrityCheck;
}
bool checkLBEArrayIntegrity(bool verbose) {
bool integrityCheck = TRUE;
int itemCnt = 0;
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"LBENODE integrity check start: checking soldier items...");
for (int i = 0; i < CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS; i++) {
if (!gCharactersList[i].fValid || gCharactersList[i].usSolID < 0) continue;
int id = gCharactersList[i].usSolID;
SOLDIERTYPE soldier = Menptr[id];
if (verbose)ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"LBENODE integrity check start: checking soldier items (%s)...", soldier.name);
for (int j = 0; j < soldier.inv.size(); j++) {
OBJECTTYPE * object = &(soldier.inv[j]);
if (object->HasAnyActiveLBEs()) {
if (!checkObjectLBEIntegrity(object)) {
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"> LBENODE missing: %s -> %s!", soldier.name, Item[object->usItem].szItemName);
integrityCheck = false;
}
else {
if (verbose)ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"> OK: %s -> %s", soldier.name, Item[object->usItem].szItemName);
}
}
else {
if (verbose)ScreenMsg(FONT_MCOLOR_LTGRAY, MSG_INTERFACE, L"> SKIP: %s -> %s", soldier.name, Item[object->usItem].szItemName);
}
}
}
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"LBENODE integrity check start: checking around %i world items", gWorldItems.size());
for (std::vector<WORLDITEM>::iterator worldItem = gWorldItems.begin(); worldItem != gWorldItems.end(); ++worldItem)
{
OBJECTTYPE* object = &(worldItem->object);
if (object->HasAnyActiveLBEs()) {
if (!checkObjectLBEIntegrity(object)) {
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"> LBENODE missing: loaded sector -> %s!", Item[object->usItem].szItemName);
integrityCheck = false;
}
else {
if (verbose)ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"> OK: loaded sector -> %s", Item[object->usItem].szItemName);
}
}
else {
if (verbose)ScreenMsg(FONT_MCOLOR_LTGRAY, MSG_INTERFACE, L"> SKIP: loaded sector -> %s", Item[object->usItem].szItemName);
}
itemCnt++;
}
if (integrityCheck) {
ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"LBENODE integrity check passed!");
}
else {
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Missing LBENODE(s) detected! Restart the game and check last save for corruption.");
}
return integrityCheck;
}
bool IsSlotAnLBESlot(int slot)
{
switch(slot) {
@@ -179,13 +259,15 @@ void MoveItemsInSlotsToLBE( SOLDIERTYPE *pSoldier, std::vector<INT8>& LBESlots,
// CHRISL: New function to move items from default pockets to usable pockets
BOOLEAN MoveItemsToActivePockets( SOLDIERTYPE *pSoldier, std::vector<INT8>& LBESlots, UINT32 uiHandPos, OBJECTTYPE *pObj )
{
BOOLEAN flag=FALSE;
BOOLEAN flag= FALSE;
if(pObj->IsActiveLBE(0) == false) {
CreateLBE(pObj, pSoldier->ubID, LBESlots.size());
}
LBENODE* pLBE = pObj->GetLBEPointer(0);
if (!pLBE) return FALSE;
MoveItemsInSlotsToLBE(pSoldier, LBESlots, pLBE, pObj);
DestroyLBEIfEmpty(pObj);
@@ -327,7 +409,7 @@ BOOLEAN MoveItemToLBEItem( SOLDIERTYPE *pSoldier, UINT32 uiHandPos )
CreateLBE(&(pSoldier->inv[uiHandPos]), pSoldier->ubID, LBESlots.size());
LBENODE* pLBE = pSoldier->inv[uiHandPos].GetLBEPointer(0);
for(unsigned int i=0; i<LBESlots.size(); i++)
for(unsigned int i=0; pLBE && i<LBESlots.size(); i++)
{
// Is there an item in this pocket?
if(pSoldier->inv[LBESlots[i]].exists() == true)
@@ -359,7 +441,7 @@ BOOLEAN MoveItemFromLBEItem( SOLDIERTYPE *pSoldier, UINT32 uiHandPos, OBJECTTYPE
}
LBENODE* pLBE = pObj->GetLBEPointer(0);
for(unsigned int i=0; i<LBESlots.size(); i++)
for(unsigned int i=0; pLBE && i<LBESlots.size(); i++)
{
// Is there an item in this LBE pocket?
if(pLBE->inv[i].exists() == true)
@@ -480,18 +562,38 @@ bool OBJECTTYPE::HasAnyActiveLBEs(SOLDIERTYPE * pSoldier, UINT8 iter)
LBENODE* OBJECTTYPE::GetLBEPointer(unsigned int index)
{
CHAR16 msgTemp[150];
if (LBEArray.empty() == false) {
int uniqueID = (*this)[index]->data.lbe.uniqueID;
for (std::list<LBENODE>::iterator iter = LBEArray.begin(); iter != LBEArray.end(); ++iter) {
if (iter->uniqueID == uniqueID) {
return &(*iter);
}
}
//BOB: if we got here somehow it means we're missing LBE data for this uniqueID
{
swprintf(msgTemp, L"> Missing LBENODE for %s!", Item[this->usItem].szItemName);
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, msgTemp);
// mark as no longer active LBE
(*this)[index]->data.lbe.bLBE = 0;
}
return NULL;
}
//CHRISL: if the LBEArray is empty, we probably need to force the creation of an entry so that future functions don't crash.
//return NULL;
LBEArray.resize(1);
return &(*LBEArray.begin());
else //BOB: only do this if the LBEArray was actually empty! Otherwise this would create a cascading clusterfuck of missing LBE data.
{
//CHRISL: if the LBEArray is empty, we probably need to force the creation of an entry so that future functions don't crash.
swprintf(msgTemp, L"Reinit LBEArray!");
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, msgTemp);
LBEArray.resize(1);
return &(*LBEArray.begin());
}
}
bool OBJECTTYPE::exists()
+2
View File
@@ -254,6 +254,8 @@ public:
std::vector<OBJECTTYPE> inv;
};
#define SIZEOF_LBENODE_POD (offsetof(LBENODE, endOfPOD))
bool checkLBEArrayIntegrity(bool verbose=false); // BOB: checks all worldItems for missing LBE info
void CreateLBE(OBJECTTYPE* pObj, UINT8 ubID, int numSubPockets);
bool DestroyLBEIfEmpty(OBJECTTYPE* pObj);
void DestroyLBE(OBJECTTYPE* pObj);
+1 -1
View File
@@ -4836,7 +4836,7 @@ BOOLEAN OBJECTTYPE::AttachObjectNAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttac
}
LBENODE* pLBE = pAttachment->GetLBEPointer(0);
for(unsigned int i=0; i<LBESlots.size(); i++)
for(unsigned int i=0; pLBE && i<LBESlots.size(); i++)
{
// Is there an item in this LBE pocket?
if( pLBE->inv[i].exists() )
+1 -1
View File
@@ -989,7 +989,7 @@ void RandomizeMerc(UINT8 profile_id, MERCPROFILESTRUCT* merc, BOOL random_gear_k
}
//sidearm for snipers/rifle users (50% chance), and sometimes to just someone randomly (10% chance).
if (((weapon->ubWeaponType == GUN_SN_RIFLE || weapon->ubWeaponType == GUN_SN_RIFLE) && Random(2) < 1) || (Random(10) < 1 && weapon->ubWeaponType != GUN_PISTOL))
if ((( weapon->ubWeaponType == GUN_SN_RIFLE || weapon->ubWeaponType == GUN_RIFLE) && Random(2) < 1) || (Random(10) < 1 && weapon->ubWeaponType != GUN_PISTOL))
{
INVTYPE* pistol = GearGetRandomWeapon(min_kit_level, max_kit_level - 1, GUN_PISTOL, -1);
+1 -1
View File
@@ -22397,7 +22397,7 @@ BOOLEAN IsValidArtilleryOrderSector( INT16 sSectorX, INT16 sSectorY, INT8 bSecto
UINT16 usEnemies = (UINT16)NumNonPlayerTeamMembersInSector( sSectorX, sSectorY, ENEMY_TEAM );
UINT16 usMilitia = (UINT16)NumNonPlayerTeamMembersInSector( sSectorX, sSectorY, MILITIA_TEAM );
UINT16 usMercs = NumPlayerTeamMembersInSector( sSectorX, sSectorY, bSectorZ );
UINT16 usMercs = (UINT16)PlayerMercsInSector( (UINT8)sSectorX, (UINT8)sSectorY, (UINT8)bSectorZ );
SECTORINFO *pSectorInfo = &(SectorInfo[SECTOR( sSectorX, sSectorY )]);
+4 -1
View File
@@ -1101,7 +1101,10 @@ void StartInterrupt( void )
if ( !gfHiddenInterrupt )
{
// Stop this guy....
if (MercPtrs[LATEST_INTERRUPT_GUY]->exists() )//MM: this was crashing if the LATEST_INTERRUPT_GUY wasn't set
if ( LATEST_INTERRUPT_GUY != END_OF_INTERRUPTS // BOB: is this just a blank?
&& LATEST_INTERRUPT_GUY <= TOTAL_SOLDIERS // BOB: sanity check
&& MercPtrs[LATEST_INTERRUPT_GUY]->exists() //MM: this was crashing if the LATEST_INTERRUPT_GUY wasn't set
)
{
MercPtrs[ LATEST_INTERRUPT_GUY ]->AdjustNoAPToFinishMove( TRUE );
MercPtrs[ LATEST_INTERRUPT_GUY ]->flags.bTurningFromPronePosition = TURNING_FROM_PRONE_OFF;
+10 -1
View File
@@ -2208,7 +2208,16 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
{
if ( !InKeyRingPopup( ) )
{
if ( _KeyDown( SHIFT ) )
if (_KeyDown(CTRL))
{
checkLBEArrayIntegrity();
}
else if (_KeyDown(ALT))
{
checkLBEArrayIntegrity(true);
}
else if (_KeyDown(SHIFT))
{
SOLDIERTYPE *pNewSoldier;
INT32 iCurrentSquad;