From 89e2bd077a89f42d86528685a42b445504eb65d8 Mon Sep 17 00:00:00 2001 From: Flugente Date: Sun, 27 Jun 2021 12:20:46 +0000 Subject: [PATCH] New feature: additional decals adds blood spatters and structural wear on walls Requires GameDir >= r2595 to work git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@9113 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- GameSettings.cpp | 3 + GameSettings.h | 3 + GameVersion.cpp | 4 +- Tactical/LOS.cpp | 121 ++++++++++++++++ TileEngine/SaveLoadMap.cpp | 72 +++++++--- TileEngine/SaveLoadMap.h | 1 + TileEngine/Structure Internals.h | 8 +- TileEngine/renderworld.cpp | 227 +++++++++++++++++++++++++++++++ TileEngine/structure.cpp | 4 + 9 files changed, 420 insertions(+), 23 deletions(-) diff --git a/GameSettings.cpp b/GameSettings.cpp index 9bfd4b84..45426830 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -937,6 +937,9 @@ void LoadGameExternalOptions() // anv: hide stuff on roof in explored rooms at ground level view (sandbags and other crap) gGameExternalOptions.fHideExploredRoomRoofStructures = iniReader.ReadBoolean("Graphics Settings", "HIDE_EXPLORED_ROOM_ROOF_STRUCTURES", TRUE); + // Flugente: additional decals on objects (cracked walls, blood spatters etc.) + gGameExternalOptions.fAdditionalDecals = iniReader.ReadBoolean( "Graphics Settings", "ADDITIONAL_DECALS", FALSE ); + //################# Sound Settings ################# gGameExternalOptions.guiWeaponSoundEffectsVolume = iniReader.ReadInteger("Sound Settings","WEAPON_SOUND_EFFECTS_VOLUME", 0, 0, 1000 /*1000 = 10x?*/); diff --git a/GameSettings.h b/GameSettings.h index d799902a..b45ebb51 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -898,6 +898,9 @@ typedef struct BOOLEAN fAutoHideProgressBar; // anv: hide stuff on roof in explored rooms at ground level view (sandbags and other crap) BOOLEAN fHideExploredRoomRoofStructures; + + BOOLEAN fAdditionalDecals; // Flugente: show additional decals on objects (cracked walls, blood spatters etc.) + //enable ext mouse key BOOLEAN bAltAimEnabled; BOOLEAN bAimedBurstEnabled; diff --git a/GameVersion.cpp b/GameVersion.cpp index 3d3e1c41..02109eae 100644 --- a/GameVersion.cpp +++ b/GameVersion.cpp @@ -55,8 +55,8 @@ #endif -CHAR8 czVersionNumber[16] = { "Build 21.04.26" }; //YY.MM.DD +CHAR8 czVersionNumber[16] = { "Build 21.06.27" }; //YY.MM.DD CHAR16 zTrackingNumber[16] = { L"Z" }; -CHAR16 zRevisionNumber[16] = { L"Revision 8980" }; +CHAR16 zRevisionNumber[16] = { L"Revision 9113" }; // SAVE_GAME_VERSION is defined in header, change it there diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index c2bfd602..a6f16e90 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -57,6 +57,7 @@ #include "SkillCheck.h" // added by Flugente #include "ai.h" // sevenfm #include "GameInitOptionsScreen.h" +#include "renderworld.h" // added by Flugente for SetRenderFlags( RENDER_FLAG_FULL ); //forward declarations of common classes to eliminate includes class OBJECTTYPE; @@ -3291,6 +3292,126 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend send_hit( &SWeaponHit ); } } + + // Flugente: add blood spatter to wall next to target + if ( gGameExternalOptions.fAdditionalDecals + &&( pTarget->ubBodyType < ADULTFEMALEMONSTER || (pTarget->ubBodyType >= FATCIV && pTarget->ubBodyType <= BLOODCAT) ) + && iDamage > 15 ) + { + // the direction in SWeaponHit.usDirection is erversed for whatever reason + UINT8 properdirection = gOppositeDirection[SWeaponHit.usDirection]; + + if ( properdirection == SOUTHWEST + ||properdirection == WEST + || properdirection == NORTHWEST + || properdirection == NORTH + || properdirection == NORTHEAST) + { + bool northwestalreadydone( false ); + + INT32 nextGridNoinSight = pBullet->sGridNo; + + // If we're firing straight up (NORTHWEST), issues arise if we hit a corner. + // If it's an outside corner, it would be enough to simply mark both outside walls. + // This does not work in an inside corner, as the walls would be tied to the northern and western gridno from our position, not the northwest one. + // It could also be the case that it's an inside corner in a full wall. + // Solution: First check the northern and western gridnos for walls. Only if those don't exist, continue to the northwest gridno and check it's outside walls. + if ( properdirection == NORTHWEST ) + { + nextGridNoinSight = NewGridNo( pBullet->sGridNo, DirectionInc( WEST ) ); + + if ( gubWorldMovementCosts[nextGridNoinSight][WEST][0] >= TRAVELCOST_BLOCKED ) + { + STRUCTURE* pStructureForBlood = FindStructure( nextGridNoinSight, STRUCTURE_WALL ); + while ( pStructureForBlood ) + { + // add if not already set + // add if of proper height + if ( ( pStructureForBlood->ubWallOrientation == INSIDE_TOP_RIGHT ) ) + { + northwestalreadydone = true; + + if ( !( pStructureForBlood->ubDecalFlag & STRUCTURE_DECALFLAG_BLOOD ) + && StructureHeight( pStructureForBlood ) == 4 ) + { + // add blood to wall + pStructureForBlood->ubDecalFlag |= STRUCTURE_DECALFLAG_BLOOD; + + gpWorldLevelData[pStructureForBlood->sGridNo].uiFlags |= MAPELEMENT_STRUCTURE_DAMAGED; + + // enforce a full render, so that we can draw decals on time + SetRenderFlags( RENDER_FLAG_FULL ); + } + } + + pStructureForBlood = FindNextStructure( pStructureForBlood, STRUCTURE_WALL ); + } + } + + nextGridNoinSight = NewGridNo( pBullet->sGridNo, DirectionInc( NORTH ) ); + + if ( gubWorldMovementCosts[nextGridNoinSight][NORTH][0] >= TRAVELCOST_BLOCKED ) + { + STRUCTURE* pStructureForBlood = FindStructure( nextGridNoinSight, STRUCTURE_WALL ); + while ( pStructureForBlood ) + { + // add if not already set + // add if of proper height + if ( pStructureForBlood->ubWallOrientation == INSIDE_TOP_LEFT ) + { + northwestalreadydone = true; + + if ( !( pStructureForBlood->ubDecalFlag & STRUCTURE_DECALFLAG_BLOOD ) + && StructureHeight( pStructureForBlood ) == 4 ) + { + // add blood to wall + pStructureForBlood->ubDecalFlag |= STRUCTURE_DECALFLAG_BLOOD; + + gpWorldLevelData[pStructureForBlood->sGridNo].uiFlags |= MAPELEMENT_STRUCTURE_DAMAGED; + + // enforce a full render, so that we can draw decals on time + SetRenderFlags( RENDER_FLAG_FULL ); + } + } + + pStructureForBlood = FindNextStructure( pStructureForBlood, STRUCTURE_WALL ); + } + } + } + + nextGridNoinSight = NewGridNo( pBullet->sGridNo, DirectionInc( properdirection ) ); + + if ( !northwestalreadydone + && gubWorldMovementCosts[nextGridNoinSight][properdirection][0] >= TRAVELCOST_BLOCKED ) + { + STRUCTURE* pStructureForBlood = FindStructure( nextGridNoinSight, STRUCTURE_WALL ); + while ( pStructureForBlood ) + { + // add if not already set + // add if of proper height + if ( ( ( properdirection == NORTHWEST && ( pStructureForBlood->ubWallOrientation == OUTSIDE_TOP_LEFT || pStructureForBlood->ubWallOrientation == OUTSIDE_TOP_RIGHT ) ) + || ( properdirection == WEST && ( pStructureForBlood->ubWallOrientation == OUTSIDE_TOP_RIGHT || pStructureForBlood->ubWallOrientation == INSIDE_TOP_RIGHT ) ) + || ( properdirection == SOUTHWEST && ( pStructureForBlood->ubWallOrientation == OUTSIDE_TOP_RIGHT || pStructureForBlood->ubWallOrientation == INSIDE_TOP_RIGHT ) ) + || ( properdirection == NORTH && ( pStructureForBlood->ubWallOrientation == OUTSIDE_TOP_LEFT || pStructureForBlood->ubWallOrientation == INSIDE_TOP_LEFT ) ) + || ( properdirection == NORTHEAST && ( pStructureForBlood->ubWallOrientation == OUTSIDE_TOP_LEFT || pStructureForBlood->ubWallOrientation == INSIDE_TOP_LEFT ) ) + ) + && !( pStructureForBlood->ubDecalFlag & STRUCTURE_DECALFLAG_BLOOD ) + && StructureHeight( pStructureForBlood ) == 4 ) + { + // add blood to wall + pStructureForBlood->ubDecalFlag |= STRUCTURE_DECALFLAG_BLOOD; + + gpWorldLevelData[pStructureForBlood->sGridNo].uiFlags |= MAPELEMENT_STRUCTURE_DAMAGED; + + // enforce a full render, so that we can draw decals on time + SetRenderFlags( RENDER_FLAG_FULL ); + } + + pStructureForBlood = FindNextStructure( pStructureForBlood, STRUCTURE_WALL ); + } + } + } + } if (fStopped) { diff --git a/TileEngine/SaveLoadMap.cpp b/TileEngine/SaveLoadMap.cpp index c2d14ffd..6fc4f714 100644 --- a/TileEngine/SaveLoadMap.cpp +++ b/TileEngine/SaveLoadMap.cpp @@ -48,6 +48,7 @@ void RemoveMineFlagFromMap( INT32 usGridNo ); void SetSectorsRevealedBit( UINT32 usMapIndex ); void SetMapRevealedStatus(); void DamageStructsFromMapTempFile( MODIFY_MAP * pMap ); +void AddDecalToStructsFromMapTempFile( MODIFY_MAP * pMap ); BOOLEAN ModifyWindowStatus( INT32 uiMapIndex ); //ppp @@ -544,6 +545,10 @@ BOOLEAN LoadAllMapChangesFromMapTempFileAndApplyThem( ) RemoveMineFlagFromMap( pMap->usGridNo ); break; + case SLM_DECAL: + AddDecalToStructsFromMapTempFile( pMap ); + break; + default: AssertMsg( 0, "ERROR! Map Type not in switch when loading map changes from temp file"); break; @@ -836,11 +841,7 @@ void SaveBloodSmellAndRevealedStatesFromMapToTempFile() //if there is a structure that is damaged if( gpWorldLevelData[cnt].uiFlags & MAPELEMENT_STRUCTURE_DAMAGED ) { - STRUCTURE * pCurrent; - - pCurrent = gpWorldLevelData[cnt].pStructureHead; - - pCurrent = FindStructure( cnt, STRUCTURE_BASE_TILE ); + STRUCTURE* pCurrent = FindStructure( cnt, STRUCTURE_BASE_TILE ); //loop through all the structures and add all that are damaged while( pCurrent ) @@ -848,11 +849,10 @@ void SaveBloodSmellAndRevealedStatesFromMapToTempFile() //if the structure has been damaged if( pCurrent->ubHitPoints < pCurrent->pDBStructureRef->pDBStructure->ubHitPoints ) { - UINT8 ubBitToSet = 0x80; UINT8 ubLevel=0; if( pCurrent->sCubeOffset != 0 ) - ubLevel |= ubBitToSet; + ubLevel |= STRUCTURE_SAVEGAMELEVELFLAG; memset( &Map, 0, sizeof( MODIFY_MAP ) ); @@ -870,6 +870,23 @@ void SaveBloodSmellAndRevealedStatesFromMapToTempFile() SaveModifiedMapStructToMapTempFile( &Map, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); } + if ( pCurrent->ubDecalFlag ) + { + UINT8 ubLevel = 0; + if ( pCurrent->sCubeOffset != 0 ) + ubLevel |= STRUCTURE_SAVEGAMELEVELFLAG; + + memset( &Map, 0, sizeof( MODIFY_MAP ) ); + + Map.usGridNo = cnt; + Map.usImageType = StructureFlagToType( pCurrent->fFlags ); + Map.ubType = SLM_DECAL; + Map.ubExtra = pCurrent->ubWallOrientation | ubLevel | STRUCTURE_DECALFLAG_BLOOD; + + //Save the change to the map file + SaveModifiedMapStructToMapTempFile( &Map, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); + } + pCurrent = FindNextStructure( pCurrent, STRUCTURE_BASE_TILE ); } } @@ -1086,23 +1103,15 @@ void SetMapRevealedStatus() void DamageStructsFromMapTempFile( MODIFY_MAP * pMap ) { - STRUCTURE *pCurrent=NULL; - INT8 bLevel; - UINT8 ubWallOrientation; - UINT8 ubBitToSet = 0x80; - UINT8 ubType=0; - - //Find the base structure - pCurrent = FindStructure( pMap->usGridNo, STRUCTURE_BASE_TILE ); + STRUCTURE* pCurrent = FindStructure( pMap->usGridNo, STRUCTURE_BASE_TILE ); - if( pCurrent == NULL ) + if ( pCurrent == NULL ) return; - bLevel = pMap->ubExtra & ubBitToSet; - ubWallOrientation = pMap->ubExtra & ~ubBitToSet; - ubType = (UINT8) pMap->usImageType; - + INT8 bLevel = ( pMap->ubExtra & STRUCTURE_SAVEGAMELEVELFLAG ) ? 1 : 0; + UINT8 ubWallOrientation = pMap->ubExtra & STRUCTURE_SAVEGAMELEVELFLAG_BLK; + UINT8 ubType = (UINT8)pMap->usImageType; //Check to see if the desired strucure node is in this tile pCurrent = FindStructureBySavedInfo( pMap->usGridNo, ubType, ubWallOrientation, bLevel ); @@ -1116,6 +1125,29 @@ void DamageStructsFromMapTempFile( MODIFY_MAP * pMap ) } } +void AddDecalToStructsFromMapTempFile( MODIFY_MAP * pMap ) +{ + //Find the base structure + STRUCTURE* pCurrent = FindStructure( pMap->usGridNo, STRUCTURE_BASE_TILE ); + + if ( pCurrent == NULL ) + return; + + INT8 bLevel = ( pMap->ubExtra & STRUCTURE_SAVEGAMELEVELFLAG ) ? 1 : 0; + UINT8 ubWallOrientation = pMap->ubExtra & STRUCTURE_SAVEGAMELEVELFLAG_BLK; + UINT8 ubType = (UINT8)pMap->usImageType; + + //Check to see if the desired strucure node is in this tile + pCurrent = FindStructureBySavedInfo( pMap->usGridNo, ubType, ubWallOrientation, bLevel ); + + if ( pCurrent != NULL ) + { + pCurrent->ubDecalFlag |= STRUCTURE_DECALFLAG_BLOOD; + + gpWorldLevelData[pCurrent->sGridNo].uiFlags |= MAPELEMENT_STRUCTURE_DAMAGED; + } +} + ////////////// diff --git a/TileEngine/SaveLoadMap.h b/TileEngine/SaveLoadMap.h index 8d71015f..ff48d158 100644 --- a/TileEngine/SaveLoadMap.h +++ b/TileEngine/SaveLoadMap.h @@ -49,6 +49,7 @@ enum // sevenfm SLM_MINE_PRESENT, SLM_REMOVE_MINE_PRESENT, // silversurfer: we need this to get rid of the mine flag otherwise any tile that ever had a mine on it will forever be flagged with MAPELEMENT_PLAYER_MINE_PRESENT + SLM_DECAL, // Flugente: add decals }; typedef struct//dnl ch86 250214 diff --git a/TileEngine/Structure Internals.h b/TileEngine/Structure Internals.h index 9ad1f50d..fcf95687 100644 --- a/TileEngine/Structure Internals.h +++ b/TileEngine/Structure Internals.h @@ -123,6 +123,12 @@ extern UINT8 AtHeight[PROFILE_Z_SIZE]; #define TILE_ON_ROOF 0x01 #define TILE_PASSABLE 0x02 +// Flugente: flags that determine what decals we add on a structure +#define STRUCTURE_DECALFLAG_BLOOD 0x08 + +#define STRUCTURE_SAVEGAMELEVELFLAG_BLK 0x07 // these flags are already in use for wall orientation +#define STRUCTURE_SAVEGAMELEVELFLAG 0x80 // flag already in use for level + #define AddPosRelToBase(sBaseGridNo, pTile) (pTile->sPosRelToBase ? (sBaseGridNo + pTile->bXPosRelToBase + pTile->bYPosRelToBase * WORLD_COLS) : sBaseGridNo)//dnl ch83 080114 typedef struct TAG_STRUCTURE_TILE @@ -185,7 +191,7 @@ typedef struct TAG_STRUCTURE UINT8 ubWallOrientation; UINT8 ubVehicleHitLocation; UINT8 ubStructureHeight;// if 0, then unset; otherwise stores height of structure when last calculated - UINT8 ubUnused; + UINT8 ubDecalFlag; }STRUCTURE;// 36 bytes typedef struct TAG_STRUCTURE_FILE_REF diff --git a/TileEngine/renderworld.cpp b/TileEngine/renderworld.cpp index 9458003f..c4093b52 100644 --- a/TileEngine/renderworld.cpp +++ b/TileEngine/renderworld.cpp @@ -30,6 +30,11 @@ UINT32 guiShieldGraphic = 0; BOOLEAN fShieldGraphicInit = FALSE; +#define WALLDAMAGEGRAPHICS_MAX 2 +UINT32 guiWallDamageGraphic[WALLDAMAGEGRAPHICS_MAX] = { 0 }; +BOOLEAN fWallDamageGraphicInit[WALLDAMAGEGRAPHICS_MAX] = { FALSE }; +UINT32 guiWallBloodGraphic = 0; +BOOLEAN fWallBloodGraphicInit = FALSE; extern CHAR8 gDebugStr[128]; extern BOOLEAN fLandLayerDirty = TRUE; @@ -655,6 +660,219 @@ void ShowRiotShield( SOLDIERTYPE* pSoldier, UINT16 *pBuffer, UINT32 uiDestPitchB } } +// We can get graphical glitches here if we reserve too many background rectangles, as the entire array will be filled rapidly. +// Additionally we get graphic glitches if we never free these background rectangles. +// To prevent this, we reserve a limited amount and free them at the beginning of every rendering +#define MAX_DECALS_ONSCREEN 200 +INT32 gDecalBackgroundRectangle[MAX_DECALS_ONSCREEN] = { 0 }; +int gDecalBackgroundRectableCounter = 0; + +void ClearBackgroundRectanglesForDecal() +{ + for ( int i = 0; i < gDecalBackgroundRectableCounter; ++i ) + { + if ( gDecalBackgroundRectangle[i] != 0 && gDecalBackgroundRectangle[i] != -1 ) + { + FreeBackgroundRect( gDecalBackgroundRectangle[i] ); + gDecalBackgroundRectangle[i] = 0; + } + } + + gDecalBackgroundRectableCounter = 0; +} + +bool SetupBackgroundRectanglesForDecal( UINT32 uiFlags, INT16 *pSaveArea, INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom ) +{ + if ( gDecalBackgroundRectableCounter < MAX_DECALS_ONSCREEN ) + { + gDecalBackgroundRectangle[gDecalBackgroundRectableCounter] = RegisterBackgroundRect( uiFlags, pSaveArea, sLeft, sTop, sRight, sBottom ); + + if ( gDecalBackgroundRectangle[gDecalBackgroundRectableCounter] != -1 ) + { + SetBackgroundRectFilled( gDecalBackgroundRectangle[gDecalBackgroundRectableCounter] ); + + ++gDecalBackgroundRectableCounter; + + return true; + } + } + + return false; +} + +// Flugente: display decal +void ShowDecal( UINT16 *pBuffer, UINT32 uiDestPitchBYTES, UINT16 *pZBuffer, UINT16 usZValue, INT32 sGridNo ) +{ + // we mark locations with decals with the 'DAMAGED' flag for easier filtering + if ( gGameExternalOptions.fAdditionalDecals + && gGameSettings.fOptions[TOPTION_BLOOD_N_GORE] + && !TileIsOutOfBounds( sGridNo ) + && ( gpWorldLevelData[sGridNo].uiFlags & MAPELEMENT_STRUCTURE_DAMAGED ) ) + { + for ( int i = 0; i < WALLDAMAGEGRAPHICS_MAX; ++i ) + { + if ( !fWallDamageGraphicInit[i] ) + { + VOBJECT_DESC VObjectDesc; + VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; + + CHAR8 filename[128]; + sprintf( filename, "Tilecache\\walldamage%d.sti", i ); + + FilenameForBPP( filename, VObjectDesc.ImageFile ); + if ( !AddVideoObject( &VObjectDesc, &guiWallDamageGraphic[i] ) ) + AssertMsg( 0, String( "Missing %s", VObjectDesc.ImageFile ) ); + + fWallDamageGraphicInit[i] = TRUE; + } + } + + if ( !fWallBloodGraphicInit ) + { + VOBJECT_DESC VObjectDesc; + VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; + FilenameForBPP( "Tilecache\\bloodspatter_wall.sti", VObjectDesc.ImageFile ); + if ( !AddVideoObject( &VObjectDesc, &guiWallBloodGraphic ) ) + AssertMsg( 0, String( "Missing %s", VObjectDesc.ImageFile ) ); + + fWallBloodGraphicInit = TRUE; + } + + // rendering while scrolling is a pain in the ass, so we skip that + if ( gfScrollPending || gfScrollInertia ) + return; + + STRUCTURE* pStructure = FindStructure( sGridNo, STRUCTURE_WALL ); + if ( !pStructure ) + return; + + // Get screen pos of gridno...... + INT16 sScreenX, sScreenY; + GetGridNoScreenXY( sGridNo, &sScreenX, &sScreenY ); + + // For ease of use, the pics from the libraries are without an offset, we handle this here. Of course this assumes the painter starts with the proper template to begin with. + INT32 displayX = sScreenX - WORLD_TILE_X / 2; + INT32 displayY = sScreenY - WORLD_TILE_Y / 2 - 41; + + // we need to reserve a background if we draw decals, but we only need to do that once + bool backgroundrectregistered = false; + + //loop through all the structures and add all that are damaged + while ( pStructure ) + { + // for now only for full walls + if ( StructureHeight(pStructure) == 4 + && ( pStructure->ubWallOrientation == OUTSIDE_TOP_LEFT + || pStructure->ubWallOrientation == INSIDE_TOP_LEFT + || pStructure->ubWallOrientation == OUTSIDE_TOP_RIGHT + || pStructure->ubWallOrientation == INSIDE_TOP_RIGHT )) + { + //if the structure has been damaged + if ( pStructure->ubHitPoints < pStructure->pDBStructureRef->pDBStructure->ubHitPoints ) + { + int graphiclib = sGridNo % WALLDAMAGEGRAPHICS_MAX; + + HVOBJECT hSrcVObject; + if ( GetVideoObject( &hSrcVObject, guiWallDamageGraphic[graphiclib] ) ) + { + // redraw background to stop weird graphic remnants remaining + // but don't do so while scrolling, because that looks weird + if ( !backgroundrectregistered ) + { + if ( !SetupBackgroundRectanglesForDecal( BGND_FLAG_ANIMATED, NULL, displayX - 50, displayY - 60, displayX + 50, displayY + 60 ) ) + { + return; + } + + backgroundrectregistered = true; + } + + FLOAT ratio = (FLOAT)( pStructure->ubHitPoints ) / (FLOAT)( pStructure->pDBStructureRef->pDBStructure->ubHitPoints ); + + // The first half of the pics are for the left side, the second half for the right side + UINT16 picsperside = hSrcVObject->usNumberOfObjects / 2; + + UINT16 graphic = 0; + displayX = sScreenX - WORLD_TILE_X / 2; + + switch ( pStructure->ubWallOrientation ) + { + case OUTSIDE_TOP_LEFT: + case INSIDE_TOP_LEFT: + { + graphic = ratio * picsperside; + } + break; + + case OUTSIDE_TOP_RIGHT: + case INSIDE_TOP_RIGHT: + { + graphic = ratio * picsperside + picsperside; + displayX += 16; + } + break; + } + + if ( BltIsClippedOrOffScreen( hSrcVObject, displayX, displayY, graphic, &gClippingRect ) ) + return; + + Blt8BPPDataTo16BPPBufferTransZNB( pBuffer, uiDestPitchBYTES, pZBuffer, usZValue, hSrcVObject, displayX, displayY, graphic ); + } + } + + if ( pStructure->ubDecalFlag & STRUCTURE_DECALFLAG_BLOOD ) + { + HVOBJECT hSrcVObject; + if ( GetVideoObject( &hSrcVObject, guiWallBloodGraphic ) ) + { + // redraw background to stop weird graphic remnants remaining + // but don't do so while scrolling, because that looks weird + if ( !backgroundrectregistered ) + { + if ( !SetupBackgroundRectanglesForDecal( BGND_FLAG_ANIMATED, NULL, displayX - 50, displayY - 60, displayX + 50, displayY + 60 ) ) + { + return; + } + + backgroundrectregistered = true; + } + + // The first half of the pics are for the left side, the second half for the right side + UINT16 picsperside = hSrcVObject->usNumberOfObjects / 2; + + UINT16 graphic = 0; + displayX = sScreenX - WORLD_TILE_X / 2; + + switch ( pStructure->ubWallOrientation ) + { + case OUTSIDE_TOP_LEFT: + case INSIDE_TOP_LEFT: + // It is advised that the number of pics per side does not divide the map length per side - 160 or 360 - without remainder. + // Otherwise the spatters along a '/' wall will all be the same + graphic = ( sGridNo ) % picsperside; + break; + + case OUTSIDE_TOP_RIGHT: + case INSIDE_TOP_RIGHT: + graphic = ( sGridNo ) % picsperside + picsperside; + displayX += 16; + break; + } + + if ( BltIsClippedOrOffScreen( hSrcVObject, displayX, displayY, graphic, &gClippingRect ) ) + return; + + Blt8BPPDataTo16BPPBufferTransZNB( pBuffer, uiDestPitchBYTES, pZBuffer, usZValue, hSrcVObject, displayX, displayY, graphic ); + } + } + } + + pStructure = FindNextStructure( pStructure, STRUCTURE_WALL ); + } + } +} + + BOOLEAN RevealWalls(INT16 sX, INT16 sY, INT16 sRadius) { LEVELNODE *pStruct; @@ -1058,6 +1276,9 @@ void RenderTiles(UINT32 uiFlags, INT32 iStartPointX_M, INT32 iStartPointY_M, INT iAnchorPosX_S = iStartPointX_S; iAnchorPosY_S = iStartPointY_S; + // Flugente: clear rectangles reserved for decals + ClearBackgroundRectanglesForDecal(); + if (!(uiFlags&TILES_DIRTY)) pDestBuf = LockVideoSurface(FRAME_BUFFER, &uiDestPitchBYTES); @@ -2818,6 +3039,12 @@ void RenderTiles(UINT32 uiFlags, INT32 iStartPointX_M, INT32 iStartPointY_M, INT Blt8BPPDataTo8BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sXPos, sYPos, usImageIndex); } } + + // Flugente: additional decals + if ( fWallTile ) + { + ShowDecal( (UINT16*)pDestBuf, uiDestPitchBYTES, gpZBuffer, sZLevel, uiTileIndex ); + } } diff --git a/TileEngine/structure.cpp b/TileEngine/structure.cpp index f79fa47a..1b2fb135 100644 --- a/TileEngine/structure.cpp +++ b/TileEngine/structure.cpp @@ -49,6 +49,7 @@ #include "Animation Control.h" #include "Soldier Ani.h" #include "ASD.h" // added by Flugente + #include "renderworld.h" // added by Flugente for SetRenderFlags( RENDER_FLAG_FULL ); #endif #ifdef COUNT_PATHS @@ -1992,6 +1993,9 @@ INT8 DamageStructure( STRUCTURE * pStructure, UINT8 ubDamage, UINT8 ubReason, IN //Since the structure is being damaged, set the map element that a structure is damaged gpWorldLevelData[ sGridNo ].uiFlags |= MAPELEMENT_STRUCTURE_DAMAGED; + // Flugente: enforce a full render, so that we can draw decals on time + SetRenderFlags( RENDER_FLAG_FULL ); + // We are a little damaged.... return( 2 ); }