From 8857e0772b374aae35245b362171f5939d85cbd9 Mon Sep 17 00:00:00 2001 From: Flugente Date: Fri, 31 Oct 2014 22:13:32 +0000 Subject: [PATCH] - if a a roof collapses, any structures built on it (fans, sandbags) are destroyed - if a a roof collapses, any corpses on it are moved to the floor git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7623 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- Tactical/Rotting Corpses.cpp | 24 +++++ Tactical/Rotting Corpses.h | 3 + TileEngine/Explosion Control.cpp | 28 ++++- TileEngine/SaveLoadMap.cpp | 43 ++++++++ TileEngine/SaveLoadMap.h | 3 +- TileEngine/structure.cpp | 38 +++++++ TileEngine/structure.h | 3 + TileEngine/worldman.cpp | 172 ++++++++++++++++++++++++++++--- TileEngine/worldman.h | 7 +- 9 files changed, 304 insertions(+), 17 deletions(-) diff --git a/Tactical/Rotting Corpses.cpp b/Tactical/Rotting Corpses.cpp index b6dcad3d..b6c78d8d 100644 --- a/Tactical/Rotting Corpses.cpp +++ b/Tactical/Rotting Corpses.cpp @@ -1935,6 +1935,30 @@ BOOLEAN DecapitateCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel ) return FALSE; } +void ShiftCorpse( INT32 sGridNo, INT8 bLevel ) +{ + for ( INT32 cnt = 0; cnt < giNumRottingCorpse; ++cnt ) + { + ROTTING_CORPSE* pCorpse = &(gRottingCorpse[cnt]); + + if ( pCorpse && pCorpse->fActivated && pCorpse->def.ubType != 0 && pCorpse->def.sGridNo == sGridNo && pCorpse->def.bLevel == 1 ) + { + ROTTING_CORPSE_DEFINITION CorpseDef; + + // Copy corpse definition... + memcpy( &CorpseDef, &(pCorpse->def), sizeof(ROTTING_CORPSE_DEFINITION) ); + + // Remove old one... + RemoveCorpse( pCorpse->iID ); + + // move corpse to the other level + CorpseDef.bLevel = 1 - bLevel; + + AddRottingCorpse( &CorpseDef ); + } + } +} + // Flugente: can this corpse be gutted? BOOLEAN IsValidGutCorpse( ROTTING_CORPSE *pCorpse ) { diff --git a/Tactical/Rotting Corpses.h b/Tactical/Rotting Corpses.h index ba35fa43..2936d5fd 100644 --- a/Tactical/Rotting Corpses.h +++ b/Tactical/Rotting Corpses.h @@ -201,6 +201,9 @@ ROTTING_CORPSE *GetCorpseAtGridNo( INT32 sGridNo , INT8 bLevel ); BOOLEAN IsValidDecapitationCorpse( ROTTING_CORPSE *pCorpse ); BOOLEAN DecapitateCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel ); +// Flugente: move all corpses on sGridNo level bLevel to level 1 - bLevel +void ShiftCorpse( INT32 sGridNo, INT8 bLevel ); + // Flugente: actions for the covert opts trait BOOLEAN IsValidGutCorpse( ROTTING_CORPSE *pCorpse ); BOOLEAN GutCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel ); diff --git a/TileEngine/Explosion Control.cpp b/TileEngine/Explosion Control.cpp index 8d5f2bf0..b846b3b9 100644 --- a/TileEngine/Explosion Control.cpp +++ b/TileEngine/Explosion Control.cpp @@ -5934,6 +5934,32 @@ void RoofDestruction( INT32 sGridNo ) SoldierDropThroughRoof( pSoldier, soldierdropoffgridno ); } + // there can be non-roof structures on roofs. In order to collapse those, check for all structures who are above a certain height, and destroy them + STRUCTURE* pStruct = GetTallestStructureOnGridno( sGridNo, 1 ); + while ( pStruct ) + { + LEVELNODE* pNode = FindLevelNodeBasedOnStructure( pStruct->sGridNo, pStruct ); + + if ( pNode ) + { + if ( RemoveOnRoofStruct( sGridNo, pNode->usIndex ) ) + pStruct = GetTallestStructureOnGridno( sGridNo, 1 ); + else + break; + } + else + break; + } + + // very important: if applying changes to map files is turned on, adding corpses will corrupt the map (only noticeable if you reload it) + // for this reason we turn this off and on again + ApplyMapChangesToMapTempFile( FALSE ); + + // if there is a corpse here, drop that down as well + ShiftCorpse( sGridNo , 1); + + ApplyMapChangesToMapTempFile( TRUE ); + // play an animation of falling roof tiles // if we merely collected the tiles that collapse and then call them all together, it would be possible to have animations for multi-tile collapses static UINT16 usRoofCollapseExplosionIndex = 1727; @@ -6016,7 +6042,7 @@ void HandleRoofDestruction( INT32 sGridNo, INT16 sDamage ) (*it).second = 0; } } - + // Nodes might have been removed, and the roof might have degenerated into several networks gridnoarmournetworkmap roofnetworkmap = GetConnectedRoofNetworks( floorarmourvector ); diff --git a/TileEngine/SaveLoadMap.cpp b/TileEngine/SaveLoadMap.cpp index 6857881e..668e08a6 100644 --- a/TileEngine/SaveLoadMap.cpp +++ b/TileEngine/SaveLoadMap.cpp @@ -461,6 +461,22 @@ BOOLEAN LoadAllMapChangesFromMapTempFileAndApplyThem( ) ++uiNumberOfElementsSavedBackToFile; break; case SLM_REMOVE_ONROOF: + if ( pMap->usImageType >= FIRSTTEXTURE && pMap->usImageType <= WIREFRAMES ) + { + RemoveAllOnRoofsOfTypeRange( pMap->usGridNo, FIRSTTEXTURE, WIREFRAMES ); + } + else + { + GetTileIndexFromTypeSubIndex( pMap->usImageType, pMap->usSubImageIndex, &usIndex ); + + RemoveOnRoofAdjustSavefile( pMap->usGridNo, usIndex ); + } + + // Save this struct back to the temp file + SaveModifiedMapStructToMapTempFile( pMap, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); + + //Since the element is being saved back to the temp file, increment the # + ++uiNumberOfElementsSavedBackToFile; break; case SLM_REMOVE_TOPMOST: break; @@ -706,6 +722,33 @@ void RemoveRoofFromMapTempFile( INT32 uiMapIndex, UINT16 usIndex ) SaveModifiedMapStructToMapTempFile( &Map, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); } +void RemoveOnRoofFromMapTempFile( INT32 uiMapIndex, UINT16 usIndex ) +{ + MODIFY_MAP Map; + UINT32 uiType; + UINT16 usSubIndex; + + if ( !gfApplyChangesToTempFile ) + return; + + if ( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) + return; + + GetTileType( usIndex, &uiType ); + GetSubIndexFromTileIndex( usIndex, &usSubIndex ); + + memset( &Map, 0, sizeof(MODIFY_MAP) ); + + Map.usGridNo = uiMapIndex; + // Map.usIndex = usIndex; + Map.usImageType = (UINT16)uiType; + Map.usSubImageIndex = usSubIndex; + + Map.ubType = SLM_REMOVE_ONROOF; + + SaveModifiedMapStructToMapTempFile( &Map, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); +} + void RemoveSavedStructFromMap( INT32 uiMapIndex, UINT16 usIndex ) { diff --git a/TileEngine/SaveLoadMap.h b/TileEngine/SaveLoadMap.h index 0c5ad8ba..8b0cdabb 100644 --- a/TileEngine/SaveLoadMap.h +++ b/TileEngine/SaveLoadMap.h @@ -82,8 +82,9 @@ BOOLEAN LoadAllMapChangesFromMapTempFileAndApplyThem( ); void RemoveStructFromMapTempFile( INT32 uiMapIndex, UINT16 usIndex ); -// Flugente: permanently remove roof tiles +// Flugente: permanently remove other tiles void RemoveRoofFromMapTempFile( INT32 uiMapIndex, UINT16 usIndex ); +void RemoveOnRoofFromMapTempFile( INT32 uiMapIndex, UINT16 usIndex ); void AddRemoveObjectToMapTempFile( INT32 uiMapIndex, UINT16 usIndex ); diff --git a/TileEngine/structure.cpp b/TileEngine/structure.cpp index 166533c7..254fc0e5 100644 --- a/TileEngine/structure.cpp +++ b/TileEngine/structure.cpp @@ -2460,6 +2460,44 @@ BOOLEAN FiniStructureDB( void ) return( TRUE ); } +STRUCTURE* GetTallestStructureOnGridno( INT32 sGridNo, INT8 bLevel ) +{ + STRUCTURE* pCurrent = NULL; + STRUCTURE* pStruct = NULL; + INT8 bestheight = -1; + INT16 sDesiredLevel = STRUCTURE_ON_GROUND; + + if ( bLevel ) + sDesiredLevel = STRUCTURE_ON_ROOF; + + pCurrent = gpWorldLevelData[sGridNo].pStructureHead; + + while ( pCurrent != NULL ) + { + // Check level! + if ( pCurrent->sCubeOffset == sDesiredLevel ) + { + if ( pCurrent->fFlags & (STRUCTURE_CORPSE | STRUCTURE_PERSON | STRUCTURE_ROOF) ) + { + // we are interested in building tiles, not people + pCurrent = pCurrent->pNext; + continue; + } + + INT8 height = StructureHeight( pCurrent ); + if ( height > bestheight ) + { + bestheight = height; + pStruct = pCurrent; + } + } + + pCurrent = pCurrent->pNext; + } + + return pStruct; +} + INT8 GetBlockingStructureInfo( INT32 sGridNo, INT8 bDir, INT8 bNextDir, INT8 bLevel, INT8 *pStructHeight, STRUCTURE ** ppTallestStructure, BOOLEAN fWallsBlock ) { diff --git a/TileEngine/structure.h b/TileEngine/structure.h index 9415915e..dd3a9f14 100644 --- a/TileEngine/structure.h +++ b/TileEngine/structure.h @@ -82,6 +82,9 @@ void DebugStructurePage1( void ); BOOLEAN AddZStripInfoToVObject( HVOBJECT hVObject, STRUCTURE_FILE_REF * pStructureFileRef, BOOLEAN fFromAnimation, INT16 sSTIStartIndex ); +// Flugente: return the highest structure (no person, roof or corpse) on a gridno and level +STRUCTURE* GetTallestStructureOnGridno( INT32 sGridNo, INT8 bLevel ); + // FUNCTIONS FOR DETERMINING STUFF THAT BLOCKS VIEW FOR TILE_bASED LOS INT8 GetBlockingStructureInfo( INT32 sGridNo, INT8 bDir, INT8 bNextDir, INT8 bLevel, INT8 *pStructHeight, STRUCTURE ** ppTallestStructure, BOOLEAN fWallsBlock ); diff --git a/TileEngine/worldman.cpp b/TileEngine/worldman.cpp index 3aed4a13..133464ea 100644 --- a/TileEngine/worldman.cpp +++ b/TileEngine/worldman.cpp @@ -1429,7 +1429,7 @@ BOOLEAN RemoveStruct( INT32 iMapIndex, UINT16 usIndex ) if ( pOldStruct == NULL ) { // It's the head - gpWorldLevelData[ iMapIndex ].pStructHead = pStruct->pNext; + gpWorldLevelData[iMapIndex].pStructHead = pStruct->pNext; } else { @@ -1462,7 +1462,7 @@ BOOLEAN RemoveStruct( INT32 iMapIndex, UINT16 usIndex ) } } MemFree( pStruct ); - guiLevelNodes--; + --guiLevelNodes; return( TRUE ); } @@ -1476,10 +1476,75 @@ BOOLEAN RemoveStruct( INT32 iMapIndex, UINT16 usIndex ) RemoveWorldFlagsFromNewNode( iMapIndex, usIndex ); return( FALSE ); - } -// Flugente: permanently remove roof tiles +// same as RemoveStruct(...), except that this focuses on .pOnRoofHead instead of .pStructHead +BOOLEAN RemoveOnRoofStruct( INT32 iMapIndex, UINT16 usIndex ) +{ + LEVELNODE *pStruct = NULL; + LEVELNODE *pOldStruct = NULL; + + pStruct = gpWorldLevelData[iMapIndex].pOnRoofHead; + + // Look through all structs and remove index if found + while ( pStruct != NULL ) + { + if ( pStruct->usIndex == usIndex ) + { + // OK, set links + // Check for head or tail + if ( pOldStruct == NULL ) + { + // It's the head + gpWorldLevelData[iMapIndex].pOnRoofHead = pStruct->pNext; + } + else + { + pOldStruct->pNext = pStruct->pNext; + } + + //Check for special flag to stop burn-through on same-tile structs... + if ( pStruct->pStructureData != NULL ) + { + // If we are NOT a wall and NOT multi-tiles, set mapelement flag... + //if ( !( pStruct->pStructureData->fFlags & STRUCTURE_WALLSTUFF ) && pStruct->pStructureData->pDBStructureRef->pDBStructure->ubNumberOfTiles == 1 ) + //{ + // UNSet flag... + // gpWorldLevelData[ iMapIndex ].ubExtFlags[0] &= ( ~MAPELEMENT_EXT_NOBURN_STRUCT ); + //} + } + + // Delete memory assosiated with item + DeleteStructureFromWorld( pStruct->pStructureData ); + + //If we have to, make sure to remove this node when we reload the map from a saved game + RemoveOnRoofFromMapTempFile( iMapIndex, usIndex ); + + if ( usIndex < giNumberOfTiles ) + { + // Check flags for tiledat and set a shadow if we have a buddy + if ( !GridNoIndoors( iMapIndex ) && gTileDatabase[usIndex].uiFlags & HAS_SHADOW_BUDDY && gTileDatabase[usIndex].sBuddyNum != -1 ) + { + RemoveShadow( iMapIndex, gTileDatabase[usIndex].sBuddyNum ); + } + } + MemFree( pStruct ); + --guiLevelNodes; + + return(TRUE); + } + + pOldStruct = pStruct; + pStruct = pStruct->pNext; + } + + // Could not find it, return FALSE + RemoveWorldFlagsFromNewNode( iMapIndex, usIndex ); + + return(FALSE); +} + +// Flugente: permanently remove structures BOOLEAN RemoveRoofAdjustSavefile( INT32 iMapIndex, UINT16 usIndex ) { LEVELNODE *pStruct = NULL; @@ -1527,6 +1592,53 @@ BOOLEAN RemoveRoofAdjustSavefile( INT32 iMapIndex, UINT16 usIndex ) return(FALSE); } +BOOLEAN RemoveOnRoofAdjustSavefile( INT32 iMapIndex, UINT16 usIndex ) +{ + LEVELNODE *pStruct = NULL; + LEVELNODE *pOldStruct = NULL; + + pStruct = gpWorldLevelData[iMapIndex].pOnRoofHead; + + // Look through all structs and remove index if found + + while ( pStruct != NULL ) + { + if ( pStruct->usIndex == usIndex ) + { + // OK, set links + // Check for head or tail + if ( pOldStruct == NULL ) + { + // It's the head + gpWorldLevelData[iMapIndex].pOnRoofHead = pStruct->pNext; + } + else + { + pOldStruct->pNext = pStruct->pNext; + } + + // Delete memory assosiated with item + DeleteStructureFromWorld( pStruct->pStructureData ); + + //If we have to, make sure to remove this node when we reload the map from a saved game + RemoveOnRoofFromMapTempFile( iMapIndex, usIndex ); + + MemFree( pStruct ); + --guiLevelNodes; + + return(TRUE); + } + + pOldStruct = pStruct; + pStruct = pStruct->pNext; + } + + // Could not find it, return FALSE + RemoveWorldFlagsFromNewNode( iMapIndex, usIndex ); + + return(FALSE); +} + BOOLEAN RemoveStructFromLevelNode( INT32 iMapIndex, LEVELNODE *pNode ) { @@ -1632,7 +1744,7 @@ BOOLEAN RemoveAllStructsOfTypeRange( INT32 iMapIndex, UINT32 fStartType, UINT32 return fRetVal; } -// Flugente: permanently remove roof tiles +// Flugente: permanently remove structures BOOLEAN RemoveAllRoofsOfTypeRangeAdjustSaveFile( INT32 iMapIndex, UINT32 fStartType, UINT32 fEndType ) { LEVELNODE *pStruct = NULL; @@ -1672,6 +1784,45 @@ BOOLEAN RemoveAllRoofsOfTypeRangeAdjustSaveFile( INT32 iMapIndex, UINT32 fStartT return fRetVal; } +BOOLEAN RemoveAllOnRoofsOfTypeRangeAdjustSaveFile( INT32 iMapIndex, UINT32 fStartType, UINT32 fEndType ) +{ + LEVELNODE *pStruct = NULL; + LEVELNODE *pOldStruct = NULL; + UINT32 fTileType; + BOOLEAN fRetVal = FALSE; + + LEVELNODE *pRoof = NULL; + LEVELNODE *pOldRoof = NULL; + + pRoof = gpWorldLevelData[iMapIndex].pOnRoofHead; + + // Look through all Roofs and Search for type + + if ( pRoof != NULL ) + { + if ( pRoof->usIndex != NO_TILE ) + { + GetTileType( pRoof->usIndex, &fTileType ); + + // Advance to next + pOldRoof = pRoof; + pRoof = pRoof->pNext; + + if ( fTileType >= fStartType && fTileType <= fEndType ) + { + // Remove Item + if ( pOldRoof->usIndex < giNumberOfTiles ) + { + RemoveOnRoofAdjustSavefile( iMapIndex, pOldRoof->usIndex ); + fRetVal = TRUE; + } + } + } + } + + return fRetVal; +} + //Kris: This was a serious problem. When saving the map and then reloading it, the structure // information was invalid if you changed the types, etc. This is the bulletproof way. BOOLEAN ReplaceStructIndex( INT32 iMapIndex, UINT16 usOldIndex, UINT16 usNewIndex ) @@ -2741,9 +2892,9 @@ void AdjustAllRoofShadeLevels( INT32 iMapIndex, INT8 bShadeDiff ) BOOLEAN RemoveAllRoofsOfTypeRange( INT32 iMapIndex, UINT32 fStartType, UINT32 fEndType ) { LEVELNODE *pRoof = NULL; - LEVELNODE *pOldRoof = NULL; - UINT32 fTileType; - BOOLEAN fRetVal = FALSE; + LEVELNODE *pOldRoof = NULL; + UINT32 fTileType; + BOOLEAN fRetVal = FALSE; pRoof = gpWorldLevelData[ iMapIndex ].pRoofHead; @@ -2751,10 +2902,8 @@ BOOLEAN RemoveAllRoofsOfTypeRange( INT32 iMapIndex, UINT32 fStartType, UINT32 fE while( pRoof != NULL ) { - if ( pRoof->usIndex != NO_TILE ) { - GetTileType( pRoof->usIndex, &fTileType ); // Advance to next @@ -2767,15 +2916,12 @@ BOOLEAN RemoveAllRoofsOfTypeRange( INT32 iMapIndex, UINT32 fStartType, UINT32 fE RemoveRoof( iMapIndex, pOldRoof->usIndex ); fRetVal = TRUE; } - } - } // Could not find it, return FALSE return fRetVal; - } void RemoveRoofIndexFlagsFromTypeRange( INT32 iMapIndex, UINT32 fStartType, UINT32 fEndType, UINT32 uiFlags ) diff --git a/TileEngine/worldman.h b/TileEngine/worldman.h index e7e1c3d6..d4819b44 100644 --- a/TileEngine/worldman.h +++ b/TileEngine/worldman.h @@ -69,9 +69,11 @@ BOOLEAN WaterTooDeepForAttacks( INT32 sGridNo ); // Structure manipulation routines BOOLEAN RemoveStruct( INT32 iMapIndex, UINT16 usIndex ); +BOOLEAN RemoveOnRoofStruct( INT32 iMapIndex, UINT16 usIndex ); -// Flugente: permanently remove roof tiles +// Flugente: permanently remove structures BOOLEAN RemoveRoofAdjustSavefile( INT32 iMapIndex, UINT16 usIndex ); +BOOLEAN RemoveOnRoofAdjustSavefile( INT32 iMapIndex, UINT16 usIndex ); LEVELNODE *AddStructToTail( INT32 iMapIndex, UINT16 usIndex ); LEVELNODE *AddStructToTailCommon( INT32 iMapIndex, UINT16 usIndex, BOOLEAN fAddStructDBInfo ); @@ -81,8 +83,9 @@ BOOLEAN AddStructToHead( INT32 iMapIndex, UINT16 usIndex ); BOOLEAN TypeExistsInStructLayer( INT32 iMapIndex, UINT32 fType, UINT16 *pusStructIndex ); BOOLEAN RemoveAllStructsOfTypeRange( INT32 iMapIndex, UINT32 fStartType, UINT32 fEndType ); -// Flugente: permanently remove roof tiles +// Flugente: permanently remove structures BOOLEAN RemoveAllRoofsOfTypeRangeAdjustSaveFile( INT32 iMapIndex, UINT32 fStartType, UINT32 fEndType ); +BOOLEAN RemoveAllOnRoofsOfTypeRangeAdjustSaveFile( INT32 iMapIndex, UINT32 fStartType, UINT32 fEndType ); BOOLEAN AddWallToStructLayer( INT32 iMapIndex, UINT16 usIndex, BOOLEAN fReplace ); BOOLEAN ReplaceStructIndex( INT32 iMapIndex, UINT16 usOldIndex, UINT16 usNewIndex );