Fix: It is possible to leave a sector while an explosion has been activated but not yet occured. In this case the game waits for the explosion to occur before hadnling AI, resulting in a deadlock. For more info on this bug, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&th=22909&start=0&

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8026 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2016-01-17 16:00:42 +00:00
parent 4cf9f557f8
commit b4179aeeeb
3 changed files with 149 additions and 128 deletions
+3
View File
@@ -6245,6 +6245,9 @@ BOOLEAN HandleDefiniteUnloadingOfWorld( UINT8 ubUnloadCode )
RemoveAllActiveTimedBombs();
// Flugente: remove any marker that an explosion is active but has not yet occured (to be used when leaving a sector)
RemoveActiveExplosionMarkers( );
// handle any quest stuff here so world items can be affected
HandleQuestCodeOnSectorExit( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
+143 -128
View File
@@ -3961,118 +3961,122 @@ void HandleExplosionQueue( void )
uiCurrentTime = GetJA2Clock();
// WDS 07/25/2008 - Avoid error where gWorldItems and/or gWorldBombs is nil
if (gWorldBombs && !gWorldItems.empty()) {//dnl ch75 271013
for ( uiIndex = 0; uiIndex < gubElementsOnExplosionQueue; uiIndex++ )
//dnl ch75 271013
if (gWorldBombs && !gWorldItems.empty())
{
if ( gExplosionQueue[ uiIndex ].fExists && uiCurrentTime >= gExplosionQueue[ uiIndex ].uiTimeStamp )
for ( uiIndex = 0; uiIndex < gubElementsOnExplosionQueue; ++uiIndex )
{
// Set off this bomb now!
// Preliminary assignments:
uiWorldBombIndex = gExplosionQueue[ uiIndex ].uiWorldBombIndex;
pObj = &( gWorldItems[ gWorldBombs[ uiWorldBombIndex ].iItemIndex ].object );
sGridNo = gWorldItems[ gWorldBombs[ uiWorldBombIndex ].iItemIndex ].sGridNo;
ubLevel = gWorldItems[ gWorldBombs[ uiWorldBombIndex ].iItemIndex ].ubLevel;
if (pObj->usItem == ACTION_ITEM && (*pObj)[0]->data.misc.bActionValue != ACTION_ITEM_BLOW_UP)
if ( gExplosionQueue[ uiIndex ].fExists && uiCurrentTime >= gExplosionQueue[ uiIndex ].uiTimeStamp )
{
PerformItemAction( sGridNo, pObj );
}
else if ( (*pObj)[0]->data.misc.usBombItem == TRIP_KLAXON )
{
PlayJA2Sample( KLAXON_ALARM, RATE_11025, SoundVolume( MIDVOLUME, sGridNo ), 5, SoundDir( sGridNo ) );
CallAvailableEnemiesTo( sGridNo );
//RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, 0 );
}
else if ( (*pObj)[0]->data.misc.usBombItem == TRIP_FLARE )
{
// sevenfm: changed pObj->usItem to Item[pObj->usItem].ubClassIndex as it should be correct explosives index
// NewLightEffect( sGridNo, (UINT8)Explosive[pObj->usItem].ubDuration, (UINT8)Explosive[pObj->usItem].ubStartRadius );
NewLightEffect( sGridNo, (UINT8)Explosive[ Item[pObj->usItem].ubClassIndex ].ubDuration, (UINT8)Explosive[ Item[pObj->usItem].ubClassIndex ].ubStartRadius );
// Set off this bomb now!
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
}
// Flugente: handle tripwire gun traps here...
// tripwire gets called and activated in ActivateSurroundingTripwire
else if ( Item[pObj->usItem].tripwire == 1 )
{
OBJECTTYPE newtripwireObject;
CreateItem( pObj->usItem, (*pObj)[0]->data.objectStatus, &newtripwireObject );
// search for attached guns
BOOLEAN fgunfound = FALSE;
OBJECTTYPE* pAttGun = NULL;
// check all attachments
attachmentList::iterator iterend = (*pObj)[0]->attachments.end();
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != iterend; ++iter)
// Preliminary assignments:
uiWorldBombIndex = gExplosionQueue[ uiIndex ].uiWorldBombIndex;
pObj = &( gWorldItems[ gWorldBombs[ uiWorldBombIndex ].iItemIndex ].object );
sGridNo = gWorldItems[ gWorldBombs[ uiWorldBombIndex ].iItemIndex ].sGridNo;
ubLevel = gWorldItems[ gWorldBombs[ uiWorldBombIndex ].iItemIndex ].ubLevel;
if (pObj->usItem == ACTION_ITEM && (*pObj)[0]->data.misc.bActionValue != ACTION_ITEM_BLOW_UP)
{
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_GUN )
PerformItemAction( sGridNo, pObj );
}
else if ( (*pObj)[0]->data.misc.usBombItem == TRIP_KLAXON )
{
PlayJA2Sample( KLAXON_ALARM, RATE_11025, SoundVolume( MIDVOLUME, sGridNo ), 5, SoundDir( sGridNo ) );
CallAvailableEnemiesTo( sGridNo );
//RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, 0 );
}
else if ( (*pObj)[0]->data.misc.usBombItem == TRIP_FLARE )
{
// sevenfm: changed pObj->usItem to Item[pObj->usItem].ubClassIndex as it should be correct explosives index
// NewLightEffect( sGridNo, (UINT8)Explosive[pObj->usItem].ubDuration, (UINT8)Explosive[pObj->usItem].ubStartRadius );
NewLightEffect( sGridNo, (UINT8)Explosive[ Item[pObj->usItem].ubClassIndex ].ubDuration, (UINT8)Explosive[ Item[pObj->usItem].ubClassIndex ].ubStartRadius );
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
}
// Flugente: handle tripwire gun traps here...
// tripwire gets called and activated in ActivateSurroundingTripwire
else if ( Item[pObj->usItem].tripwire == 1 )
{
OBJECTTYPE newtripwireObject;
CreateItem( pObj->usItem, (*pObj)[0]->data.objectStatus, &newtripwireObject );
// search for attached guns
BOOLEAN fgunfound = FALSE;
OBJECTTYPE* pAttGun = NULL;
// check all attachments
attachmentList::iterator iterend = (*pObj)[0]->attachments.end();
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != iterend; ++iter)
{
fgunfound = TRUE;
pAttGun = &(*iter);
break;
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_GUN )
{
fgunfound = TRUE;
pAttGun = &(*iter);
break;
}
}
}
if ( fgunfound && pAttGun && pAttGun->exists() )
{
// Flugente 2012-06-16: I ran into a weird bug. If activating multiple guntraps, an error would occur when placing a gun on the floor.
// The problem is the function GetFreeWorldItemIndex( ) in AddItemToWorld() in World Items.cpp.
// It gets a free index for the item that should be placed. If there is no free index, it creates a bigger array, copies the current array into it, and then deletes the old index.
// For some reason still unknown to me, this corrupts the pObj-pointer. It also corrupts the pAttGun-pointer, this is the reason I create a new object.
// I had to move some functions here to take care of that. It would be good if someone with more knowledge could take a look at this.
// fire with this gun, if possible. Afterwards place it on the floor
OBJECTTYPE object(*pAttGun);
CheckAndFireTripwireGun( &object, sGridNo, ubLevel, (*pObj)[0]->data.misc.ubBombOwner, (*pObj)[0]->data.ubDirection );
} else {
// sevenfm: blow attached items with tripwireactivation = TRUE
// no preplaced (owner=NOBODY) tripwire with explosive attachments allowed
if ( gGameExternalOptions.bAllowExplosiveAttachments && (*pObj)[0]->data.misc.ubBombOwner > 1 )
if ( fgunfound && pAttGun && pAttGun->exists() )
{
fAttFound=HandleAttachedExplosions( (UINT8) ((*pObj)[0]->data.misc.ubBombOwner - 2), CenterX( sGridNo ), CenterY( sGridNo ), 0,
sGridNo, (*pObj)[0]->data.misc.usBombItem, FALSE, ubLevel, (*pObj)[0]->data.ubDirection, pObj);
}
}
// this is important: delete the tripwire, otherwise we get into an infinite loop if there are two piecs of tripwire....
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
// if no other bomb exists here
CheckForBuriedBombsAndRemoveFlags( sGridNo, ubLevel );
// delete the flag, otherwise wire will only work once
(newtripwireObject)[0]->data.sObjectFlag &= ~TRIPWIRE_ACTIVATED;
// Flugente 2012-06-16: I ran into a weird bug. If activating multiple guntraps, an error would occur when placing a gun on the floor.
// The problem is the function GetFreeWorldItemIndex( ) in AddItemToWorld() in World Items.cpp.
// It gets a free index for the item that should be placed. If there is no free index, it creates a bigger array, copies the current array into it, and then deletes the old index.
// For some reason still unknown to me, this corrupts the pObj-pointer. It also corrupts the pAttGun-pointer, this is the reason I create a new object.
// I had to move some functions here to take care of that. It would be good if someone with more knowledge could take a look at this.
// now add a tripwire item to the floor, simulating that activating tripwire deactivates it
AddItemToPool( sGridNo, &newtripwireObject, 1, ubLevel, 0, -1 );
}
// Flugente: handle tripwire gun traps here...
// tripwire gets called and activated in ActivateSurroundingTripwire
// now for action item tripwire
else if ( pObj->usItem == ACTION_ITEM && (*pObj)[0]->data.misc.bActionValue == ACTION_ITEM_BLOW_UP && Item[(*pObj)[0]->data.misc.usBombItem].tripwire == 1 )
{
OBJECTTYPE newtripwireObject;
CreateItem( (*pObj)[0]->data.misc.usBombItem, (*pObj)[0]->data.objectStatus, &newtripwireObject );
// fire with this gun, if possible. Afterwards place it on the floor
OBJECTTYPE object(*pAttGun);
CheckAndFireTripwireGun( &object, sGridNo, ubLevel, (*pObj)[0]->data.misc.ubBombOwner, (*pObj)[0]->data.ubDirection );
}
else
{
// sevenfm: blow attached items with tripwireactivation = TRUE
// no preplaced (owner=NOBODY) tripwire with explosive attachments allowed
if ( gGameExternalOptions.bAllowExplosiveAttachments && (*pObj)[0]->data.misc.ubBombOwner > 1 )
{
fAttFound=HandleAttachedExplosions( (UINT8) ((*pObj)[0]->data.misc.ubBombOwner - 2), CenterX( sGridNo ), CenterY( sGridNo ), 0,
sGridNo, (*pObj)[0]->data.misc.usBombItem, FALSE, ubLevel, (*pObj)[0]->data.ubDirection, pObj);
}
}
// this is important: delete the tripwire, otherwise we get into an infinite loop if there are two piecs of tripwire....
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
// if no other bomb exists here
CheckForBuriedBombsAndRemoveFlags( sGridNo, ubLevel );
// delete the flag, otherwise wire will only work once
(newtripwireObject)[0]->data.sObjectFlag &= ~TRIPWIRE_ACTIVATED;
// now add a tripwire item to the floor, simulating that activating tripwire deactivates it
AddItemToPool( sGridNo, &newtripwireObject, 1, ubLevel, 0, -1 );
}
// Flugente: handle tripwire gun traps here...
// tripwire gets called and activated in ActivateSurroundingTripwire
// now for action item tripwire
else if ( pObj->usItem == ACTION_ITEM && (*pObj)[0]->data.misc.bActionValue == ACTION_ITEM_BLOW_UP && Item[(*pObj)[0]->data.misc.usBombItem].tripwire == 1 )
{
OBJECTTYPE newtripwireObject;
CreateItem( (*pObj)[0]->data.misc.usBombItem, (*pObj)[0]->data.objectStatus, &newtripwireObject );
// this is important: delete the tripwire, otherwise we get into an infinite loop if there are two piecs of tripwire....
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
// this is important: delete the tripwire, otherwise we get into an infinite loop if there are two piecs of tripwire....
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
// if no other bomb exists here
CheckForBuriedBombsAndRemoveFlags( sGridNo, ubLevel );
// if no other bomb exists here
CheckForBuriedBombsAndRemoveFlags( sGridNo, ubLevel );
// delete the flag, otherwise wire will only work once
(newtripwireObject)[0]->data.sObjectFlag &= ~TRIPWIRE_ACTIVATED;
// delete the flag, otherwise wire will only work once
(newtripwireObject)[0]->data.sObjectFlag &= ~TRIPWIRE_ACTIVATED;
// now add a tripwire item to the floor, simulating that activating tripwire deactivates it
AddItemToPool( sGridNo, &newtripwireObject, 1, ubLevel, 0, -1 );
}
else if ( (*pObj)[0]->data.ubWireNetworkFlag & ANY_ARTILLERY_FLAG )
{
UINT8 cnt = 0;
if ( (*pObj)[0]->data.ubWireNetworkFlag & ARTILLERY_STRIKE_COUNT_1 ) cnt += 1;
if ( (*pObj)[0]->data.ubWireNetworkFlag & ARTILLERY_STRIKE_COUNT_2 ) cnt += 2;
if ( (*pObj)[0]->data.ubWireNetworkFlag & ARTILLERY_STRIKE_COUNT_4 ) cnt += 4;
// now add a tripwire item to the floor, simulating that activating tripwire deactivates it
AddItemToPool( sGridNo, &newtripwireObject, 1, ubLevel, 0, -1 );
}
else if ( (*pObj)[0]->data.ubWireNetworkFlag & ANY_ARTILLERY_FLAG )
{
UINT8 cnt = 0;
if ( (*pObj)[0]->data.ubWireNetworkFlag & ARTILLERY_STRIKE_COUNT_1 ) cnt += 1;
if ( (*pObj)[0]->data.ubWireNetworkFlag & ARTILLERY_STRIKE_COUNT_2 ) cnt += 2;
if ( (*pObj)[0]->data.ubWireNetworkFlag & ARTILLERY_STRIKE_COUNT_4 ) cnt += 4;
// determine gridno to attack - smoke signal required. Otherwise, it is assumed the radio operator ordered the bombing of his OWN position
// if we cannot even find a radio operator, all bets are off - target a random gridno
@@ -4089,42 +4093,42 @@ void HandleExplosionQueue( void )
}
// not needed anymore
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
}
else
{
gfExplosionQueueMayHaveChangedSight = TRUE;
// We have to remove the item first to prevent the explosion from detonating it
// a second time :-)
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
// make sure no one thinks there is a bomb here any more!
CheckForBuriedBombsAndRemoveFlags( sGridNo, ubLevel);
// BOOM!
// bomb objects only store the SIDE who placed the bomb! :-(
if ( (*pObj)[0]->data.misc.ubBombOwner > 1 )
{
IgniteExplosion( (UINT8) ((*pObj)[0]->data.misc.ubBombOwner - 2), CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, (*pObj)[0]->data.misc.usBombItem, ubLevel, (*pObj)[0]->data.ubDirection, pObj);
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
}
else
{
// pre-placed
IgniteExplosion( NOBODY, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, (*pObj)[0]->data.misc.usBombItem, ubLevel, (*pObj)[0]->data.ubDirection );
}
}
/* if ( FindWorldItemForBuriedBombInGridNo(sGridNo, ubLevel) != -1 )
{
gpWorldLevelData[sGridNo].uiFlags |= MAPELEMENT_PLAYER_MINE_PRESENT;
gpWorldLevelData[sGridNo].uiFlags |= MAPELEMENT_ENEMY_MINE_PRESENT;
}*/
gfExplosionQueueMayHaveChangedSight = TRUE;
// Bye bye bomb
gExplosionQueue[ uiIndex ].fExists = FALSE;
// We have to remove the item first to prevent the explosion from detonating it
// a second time :-)
RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel );
// make sure no one thinks there is a bomb here any more!
CheckForBuriedBombsAndRemoveFlags( sGridNo, ubLevel);
// BOOM!
// bomb objects only store the SIDE who placed the bomb! :-(
if ( (*pObj)[0]->data.misc.ubBombOwner > 1 )
{
IgniteExplosion( (UINT8) ((*pObj)[0]->data.misc.ubBombOwner - 2), CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, (*pObj)[0]->data.misc.usBombItem, ubLevel, (*pObj)[0]->data.ubDirection, pObj);
}
else
{
// pre-placed
IgniteExplosion( NOBODY, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, (*pObj)[0]->data.misc.usBombItem, ubLevel, (*pObj)[0]->data.ubDirection );
}
}
/* if ( FindWorldItemForBuriedBombInGridNo(sGridNo, ubLevel) != -1 )
{
gpWorldLevelData[sGridNo].uiFlags |= MAPELEMENT_PLAYER_MINE_PRESENT;
gpWorldLevelData[sGridNo].uiFlags |= MAPELEMENT_ENEMY_MINE_PRESENT;
}*/
// Bye bye bomb
gExplosionQueue[ uiIndex ].fExists = FALSE;
}
}
}
}
// See if we can reduce the # of elements on the queue that we have recorded
// Easier to do it at this time rather than in the loop above
@@ -5007,7 +5011,18 @@ void RemoveAllActiveTimedBombs( void )
RemoveItemFromWorld( iItemIndex );
}
} while( iItemIndex != -1 );
}
// Flugente: remove any marker that an explosion is active but has not yet occured (to be used when leaving a sector)
void RemoveActiveExplosionMarkers( )
{
// it is enough to set the fExists-bit to 0 and to then set gubElementsOnExplosionQueue to 0. We don't need to null the structure itself
for ( UINT8 uiIndex = 0; uiIndex < gubElementsOnExplosionQueue; ++uiIndex )
{
gExplosionQueue[uiIndex].fExists = 0;
}
gubElementsOnExplosionQueue = 0;
}
UINT8 DetermineFlashbangEffect( SOLDIERTYPE *pSoldier, INT8 ubExplosionDir, BOOLEAN fInBuilding)
+3
View File
@@ -126,6 +126,9 @@ INT32 FindActiveTimedBomb( void );
BOOLEAN ActiveTimedBombExists( void );
void RemoveAllActiveTimedBombs( void );
// Flugente: remove any marker that an explosion is active but has not yet occured (to be used when leaving a sector)
void RemoveActiveExplosionMarkers();
#define GASMASK_MIN_STATUS 70
// OJW - 20091028 - Explosion damage sync