From 6cad680b02d638191d1df080a2ed13cf8d315c2b Mon Sep 17 00:00:00 2001 From: Flugente Date: Tue, 13 Jul 2021 19:50:49 +0000 Subject: [PATCH] We can now use interactive actions to alter decals on walls, so it is possible to simulate taking off an object from the scenery and add it as an item. For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&goto=363513&#msg_363513 Requires GameDir >= r2601 git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@9141 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- GameVersion.cpp | 4 +- Strategic/LuaInitNPCs.cpp | 28 +++++++++++ Tactical/Bullets.h | 1 + Tactical/Handle Items.cpp | 80 ++++++++++++++++++++++++++++++++ Tactical/Handle Items.h | 2 + Tactical/Item Types.h | 1 + Tactical/Items.h | 1 + Tactical/LOS.cpp | 42 ++++++++++++----- Tactical/Overhead.cpp | 7 +++ Tactical/bullets.cpp | 11 +++-- TacticalAI/AIUtils.cpp | 2 +- TileEngine/Explosion Control.cpp | 30 ++++++++++-- TileEngine/SmokeEffects.cpp | 78 +++++++++++++------------------ TileEngine/SmokeEffects.h | 1 + TileEngine/Tile Animation.cpp | 13 +++++- TileEngine/worlddef.h | 3 +- Utils/XML_Items.cpp | 9 ++++ 17 files changed, 244 insertions(+), 69 deletions(-) diff --git a/GameVersion.cpp b/GameVersion.cpp index 02109eae..6ebbab93 100644 --- a/GameVersion.cpp +++ b/GameVersion.cpp @@ -55,8 +55,8 @@ #endif -CHAR8 czVersionNumber[16] = { "Build 21.06.27" }; //YY.MM.DD +CHAR8 czVersionNumber[16] = { "Build 21.07.13" }; //YY.MM.DD CHAR16 zTrackingNumber[16] = { L"Z" }; -CHAR16 zRevisionNumber[16] = { L"Revision 9113" }; +CHAR16 zRevisionNumber[16] = { L"Revision 9141" }; // SAVE_GAME_VERSION is defined in header, change it there diff --git a/Strategic/LuaInitNPCs.cpp b/Strategic/LuaInitNPCs.cpp index e2129e8a..1c9a1974 100644 --- a/Strategic/LuaInitNPCs.cpp +++ b/Strategic/LuaInitNPCs.cpp @@ -864,6 +864,7 @@ static int l_CreateCivilian( lua_State *L ); static int l_BuildFortification( lua_State *L ); static int l_RemoveFortification( lua_State *L ); +static int l_DestroyAndReplaceDecal( lua_State *L ); static int l_GetFact( lua_State *L ); static int l_SetFact( lua_State *L ); @@ -1762,6 +1763,7 @@ void IniFunction(lua_State *L, BOOLEAN bQuests ) lua_register( L, "BuildFortification", l_BuildFortification ); lua_register( L, "RemoveFortification", l_RemoveFortification ); + lua_register( L, "DestroyAndReplaceDecal", l_DestroyAndReplaceDecal ); lua_register(L, "GetFact", l_GetFact ); lua_register(L, "SetFact", l_SetFact ); @@ -13126,6 +13128,32 @@ static int l_RemoveFortification( lua_State *L ) return 0; } +static int l_DestroyAndReplaceDecal( lua_State *L ) +{ + if ( lua_gettop( L ) >= 3 ) + { + INT32 sGridNo = lua_tointeger( L, 1 ); + + size_t len = 0; + const char* str = lua_tolstring( L, 2, &len ); + + UINT8 index = lua_tointeger( L, 3 ); + + ApplyMapChangesToMapTempFile( TRUE ); + + RemoveAllStructsOfTypeRange( sGridNo, FIRSTWALLDECAL, FOURTHWALLDECAL ); + RemoveAllStructsOfTypeRange( sGridNo, FIFTHWALLDECAL, EIGTHWALLDECAL ); + RemoveAllStructsOfTypeRange( sGridNo, FIRSTDECORATIONS, FOURTHDECORATIONS ); + + + BuildStructFromName( sGridNo, 0, str, index ); + + ApplyMapChangesToMapTempFile( FALSE ); + } + + return 0; +} + static int l_GetFact( lua_State *L ) { if ( lua_gettop( L ) ) diff --git a/Tactical/Bullets.h b/Tactical/Bullets.h index 5f332b1e..db087445 100644 --- a/Tactical/Bullets.h +++ b/Tactical/Bullets.h @@ -18,6 +18,7 @@ #define BULLET_FLAG_TRACER 0x0100 #define BULLET_FLAG_ANTIMATERIEL 0x0200 // Flugente: bullet can destroy structures #define BULLET_FLAG_INFECTED 0x0400 // Flugente: bullet is infected +#define BULLET_FLAG_WHITESMOKE 0x0800 // Flugente: bullet leaves a white smoke trail (for fire extinguisher) //afp-start calculate line points between two point #define BULLET_TRACER_MAX_LENGTH 60 diff --git a/Tactical/Handle Items.cpp b/Tactical/Handle Items.cpp index d5ca4947..28d25768 100644 --- a/Tactical/Handle Items.cpp +++ b/Tactical/Handle Items.cpp @@ -7694,6 +7694,86 @@ UINT8 CheckBuildFortification( INT32 sGridNo, INT8 sLevel, UINT8 usIndex, UINT32 return 1; } +BOOLEAN BuildStructFromName( INT32 sGridNo, INT8 sLevel, const char* aStr, UINT8 usIndex ) +{ + INT16 sUseObjIndex = -1; + + // needs to be a valid location + if ( TileIsOutOfBounds( sGridNo ) ) + return FALSE; + + // if we want to build on a roof, a roof is required + if ( sLevel && !FlatRoofAboveGridNo( sGridNo ) ) + return FALSE; + + // don't build in water + if ( TERRAIN_IS_WATER( GetTerrainType( sGridNo ) ) ) + return FALSE; + + // do not build into people + if ( NOBODY != WhoIsThere2( sGridNo, sLevel ) ) + return FALSE; + + // search wether structure exists in the current tilesets. If not, well, too bad + for ( INT32 iType = 0; iType < giNumberOfTileTypes; ++iType ) + { + // if tileset is from the current tileset, check that + if ( gTilesets[giCurrentTilesetID].TileSurfaceFilenames[iType][0] ) + { + if ( !_strnicmp( gTilesets[giCurrentTilesetID].TileSurfaceFilenames[iType], aStr, 10 ) ) + { + sUseObjIndex = iType; + break; + } + } + // otherwise, check first tileset (GENERIC 1) + else if ( gTilesets[0].TileSurfaceFilenames[iType][0] ) + { + if ( !_strnicmp( gTilesets[0].TileSurfaceFilenames[iType], aStr, 10 ) ) + { + sUseObjIndex = iType; + break; + } + } + } + + if ( sUseObjIndex < 0 ) + return FALSE; + + // Check with Structure Database (aka ODB) if we can put the object here! + BOOLEAN fOkayToAdd = OkayToAddStructureToWorld( sGridNo, sLevel, gTileDatabase[( gTileTypeStartIndex[sUseObjIndex] + usIndex )].pDBStructureRef, INVALID_STRUCTURE_ID ); + if ( fOkayToAdd || ( gTileDatabase[( gTileTypeStartIndex[sUseObjIndex] + usIndex )].pDBStructureRef == NULL ) ) + { + // Remove old graphic + ApplyMapChangesToMapTempFile( TRUE ); + + //dnl Remove existing structure before adding the same, seems to solve problem with stacking but still need test to be sure that is not removed something what should stay + // Actual structure info is added by the functions below + if ( sLevel ) + { + RemoveOnRoofStruct( sGridNo, (UINT16)( gTileTypeStartIndex[sUseObjIndex] + usIndex ) ); + + AddOnRoofToTail( sGridNo, (UINT16)( gTileTypeStartIndex[sUseObjIndex] + usIndex ) ); + } + else + { + RemoveStruct( sGridNo, (UINT16)( gTileTypeStartIndex[sUseObjIndex] + usIndex ) ); + + AddStructToHead( sGridNo, (UINT16)( gTileTypeStartIndex[sUseObjIndex] + usIndex ) ); + } + + RecompileLocalMovementCosts( sGridNo ); + + // Turn off permanent changes.... + ApplyMapChangesToMapTempFile( FALSE ); + SetRenderFlags( RENDER_FLAG_FULL ); + + return TRUE; + } + + return FALSE; +} + UINT16 gusTempDragBuildSoldierID = NOBODY; BOOLEAN BuildStructDrag( INT32 sGridNo, INT8 sLevel, UINT32 uiTileType, UINT8 usIndex, UINT16 usSoldierID ) diff --git a/Tactical/Handle Items.h b/Tactical/Handle Items.h index bd96f98a..b9b20865 100644 --- a/Tactical/Handle Items.h +++ b/Tactical/Handle Items.h @@ -288,6 +288,8 @@ BOOLEAN RemoveFortification( INT32 sGridNo, SOLDIERTYPE *pSoldier, OBJECTTYPE *p UINT8 CheckBuildFortification( INT32 sGridNo, INT8 sLevel, UINT8 usIndex, UINT32 usStructureconstructindex ); BOOLEAN BuildFortification( INT32 sGridNo, INT8 sLevel, UINT8 usIndex, UINT32 usStructureconstructindex ); +BOOLEAN BuildStructFromName( INT32 sGridNo, INT8 sLevel, const char* aStr, UINT8 usIndex ); + BOOLEAN CanRemoveFortification( INT32 sGridNo, INT8 sLevel, UINT32 usStructureconstructindex ); BOOLEAN RemoveFortification( INT32 sGridNo, INT8 sLevel, UINT32 usStructureconstructindex ); diff --git a/Tactical/Item Types.h b/Tactical/Item Types.h index dfe3bd19..5f43bce5 100644 --- a/Tactical/Item Types.h +++ b/Tactical/Item Types.h @@ -779,6 +779,7 @@ extern OBJECTTYPE gTempObject; // extended flagmask to UINT64 #define EMPTY_BLOOD_BAG 0x0000000100000000 // this item is a empty blood bag #define MEDICAL_SPLINT 0x0000000200000000 // this item is a medical splint that can be applied to some diseases +#define FIREEXTINGUISHER 0x0000000400000000 // this item is a fire extinguisher, which results in a white trail of smoke when firing // ---------------------------------------------------------------- diff --git a/Tactical/Items.h b/Tactical/Items.h index ebb3d4cd..a2df8d46 100644 --- a/Tactical/Items.h +++ b/Tactical/Items.h @@ -30,6 +30,7 @@ enum EXPLOSV_FLASHBANG, EXPLOSV_SIGNAL_SMOKE, EXPLOSV_SMOKE_DEBRIS, + EXPLOSV_SMOKE_FIRERETARDANT, EXPLOSV_ANY_TYPE, }; diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index 9c0a1cf5..bd01e092 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -1938,7 +1938,7 @@ INT32 LineOfSightTest( FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, // leaving a tile, check to see if it had gas in it // if ( pMapElement->ubExtFlags[0] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS) ) - if ( pMapElement->ubExtFlags[0] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS | MAPELEMENT_EXT_BURNABLEGAS | MAPELEMENT_EXT_DEBRIS_SMOKE) ) + if ( pMapElement->ubExtFlags[0] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS | MAPELEMENT_EXT_BURNABLEGAS | MAPELEMENT_EXT_DEBRIS_SMOKE | MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) ) { if ( (pMapElement->ubExtFlags[0] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_DEBRIS_SMOKE) ) && !fSmell ) { @@ -3593,7 +3593,7 @@ INT32 HandleBulletStructureInteraction( BULLET * pBullet, STRUCTURE * pStructure *pfHit = FALSE; - if (pBullet->usFlags & BULLET_FLAG_KNIFE || pBullet->usFlags & BULLET_FLAG_MISSILE || pBullet->usFlags & BULLET_FLAG_TANK_CANNON || pBullet->usFlags & BULLET_FLAG_FLAME ) + if (pBullet->usFlags & BULLET_FLAG_KNIFE || pBullet->usFlags & BULLET_FLAG_MISSILE || pBullet->usFlags & BULLET_FLAG_TANK_CANNON || pBullet->usFlags & (BULLET_FLAG_FLAME | BULLET_FLAG_WHITESMOKE) ) { // stops! *pfHit = TRUE; @@ -3746,7 +3746,7 @@ INT32 CTGTHandleBulletStructureInteraction( BULLET * pBullet, STRUCTURE * pStruc INT32 iCurrImpact; INT32 iImpactReduction; - if (pBullet->usFlags & BULLET_FLAG_KNIFE || pBullet->usFlags & BULLET_FLAG_MISSILE || pBullet->usFlags & BULLET_FLAG_FLAME || pBullet->usFlags & BULLET_FLAG_TANK_CANNON ) + if (pBullet->usFlags & BULLET_FLAG_KNIFE || pBullet->usFlags & BULLET_FLAG_MISSILE || pBullet->usFlags & (BULLET_FLAG_FLAME | BULLET_FLAG_WHITESMOKE) || pBullet->usFlags & BULLET_FLAG_TANK_CANNON ) { // knife/rocket stops when it hits anything, and people block completely return( pBullet->iImpact ); @@ -4677,7 +4677,7 @@ INT8 FireBullet( UINT8 ubFirer, BULLET * pBullet, BOOLEAN fFake ) else { //afp-start //always a fast bullet - if ( pBullet->usFlags & ( BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_KNIFE | BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME /*| BULLET_FLAG_TRACER*/ ) ) + if ( pBullet->usFlags & ( BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_KNIFE | BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_WHITESMOKE /*| BULLET_FLAG_TRACER*/ ) ) pBullet->usClockTicksPerUpdate = (Weapon[ pBullet->pFirer->usAttackingWeapon ].ubBulletSpeed + GetBulletSpeedBonus(&pBullet->pFirer->inv[pBullet->pFirer->ubAttackingHand]) ) / 10; else if (gGameSettings.fOptions[TOPTION_ALTERNATE_BULLET_GRAPHICS]) @@ -4824,6 +4824,11 @@ INT8 FireBulletGivenTargetNCTH( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, usBulletFlags |= BULLET_FLAG_FLAME; ubSpreadIndex = 2; } + else if ( Item[usHandItem].usItemFlag & FIREEXTINGUISHER ) + { + usBulletFlags |= BULLET_FLAG_WHITESMOKE; + ubSpreadIndex = 2; + } // HEADROCK HAM B2.5: Set tracer effect on/off for individual bullets in a Tracer Magazine, as part of the // New Tracer System. else if (gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0) @@ -5318,6 +5323,11 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA usBulletFlags |= BULLET_FLAG_FLAME; ubSpreadIndex = 2; } + else if ( Item[usHandItem].usItemFlag & FIREEXTINGUISHER ) + { + usBulletFlags |= BULLET_FLAG_WHITESMOKE; + ubSpreadIndex = 2; + } // HEADROCK HAM B2.5: Set tracer effect on/off for individual bullets in a Tracer Magazine, as part of the // New Tracer System. else if (gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0) @@ -5999,6 +6009,11 @@ INT8 FireBulletGivenTargetTrapOnly( SOLDIERTYPE* pThrower, OBJECTTYPE* pObj, INT usBulletFlags |= BULLET_FLAG_FLAME; ubSpreadIndex = 2; } + else if ( Item[usItem].usItemFlag & FIREEXTINGUISHER ) + { + usBulletFlags |= BULLET_FLAG_WHITESMOKE; + ubSpreadIndex = 2; + } // Flugente: anti-materiel ammo if ( AmmoTypes[ammotype].ammoflag & AMMO_ANTIMATERIEL ) @@ -6579,6 +6594,11 @@ INT8 FireBulletGivenTarget_NoObjectNoSoldier( UINT16 usItem, UINT8 ammotype, UIN usBulletFlags |= BULLET_FLAG_FLAME; ubSpreadIndex = 2; } + else if ( Item[usItem].usItemFlag & FIREEXTINGUISHER ) + { + usBulletFlags |= BULLET_FLAG_WHITESMOKE; + ubSpreadIndex = 2; + } // Flugente: anti-materiel ammo if ( AmmoTypes[ammotype].ammoflag & AMMO_ANTIMATERIEL ) @@ -7451,7 +7471,7 @@ void MoveBullet( INT32 iBullet ) // HEADROCK HAM B2.5: Changed condition to read fTracer flag directly from bullet's struct. // This is for the New Tracer System. - if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER*/ ) ) + if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_WHITESMOKE /*| BULLET_FLAG_TRACER*/ ) ) || ((gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.ubRealisticTracers == 0 && fTracer == TRUE))) { INT8 bStepsPerMove = STEPS_FOR_BULLET_MOVE_TRAILS; @@ -7460,7 +7480,7 @@ void MoveBullet( INT32 iBullet ) { bStepsPerMove = STEPS_FOR_BULLET_MOVE_SMALL_TRAILS; } - else if ( pBullet->usFlags & ( BULLET_FLAG_FLAME ) ) + else if ( pBullet->usFlags & ( BULLET_FLAG_FLAME | BULLET_FLAG_WHITESMOKE ) ) { bStepsPerMove = STEPS_FOR_BULLET_MOVE_FIRE_TRAILS; } @@ -7711,7 +7731,7 @@ void MoveBullet( INT32 iBullet ) if (fHitStructure) { // ATE: NOT if we are a special bullet like a LAW trail... - if (pStructure->fFlags & STRUCTURE_CORPSE && !( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT ) ) ) + if (pStructure->fFlags & STRUCTURE_CORPSE && !( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_WHITESMOKE ) ) ) { // ATE: In enemy territory here... ;) // Now that we have hit a corpse, make the bugger twich! @@ -7820,7 +7840,7 @@ void MoveBullet( INT32 iBullet ) // HEADROCK HAM B2.5: Changed condition to read fTracer flag directly from bullet's struct. // This is for the New Tracer System. - if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER */) ) + if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_WHITESMOKE /*| BULLET_FLAG_TRACER */) ) || ((gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.ubRealisticTracers == 0 && fTracer == TRUE))) { INT8 bStepsPerMove = STEPS_FOR_BULLET_MOVE_TRAILS; @@ -7829,7 +7849,7 @@ void MoveBullet( INT32 iBullet ) { bStepsPerMove = STEPS_FOR_BULLET_MOVE_SMALL_TRAILS; } - else if ( pBullet->usFlags & ( BULLET_FLAG_FLAME ) ) + else if ( pBullet->usFlags & ( BULLET_FLAG_FLAME | BULLET_FLAG_WHITESMOKE ) ) { bStepsPerMove = STEPS_FOR_BULLET_MOVE_FIRE_TRAILS; } @@ -7876,7 +7896,7 @@ void MoveBullet( INT32 iBullet ) //pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * gGameCTHConstants.GRAVITY_COEFFICIENT); } - else if ( (pBullet->usFlags & BULLET_FLAG_FLAME) && (dDistanceMoved > pBullet->iRange) ) + else if ( (pBullet->usFlags & (BULLET_FLAG_FLAME | BULLET_FLAG_WHITESMOKE)) && (dDistanceMoved > pBullet->iRange) ) { //pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * (gGameCTHConstants.GRAVITY_COEFFICIENT / 2) ); @@ -7891,7 +7911,7 @@ void MoveBullet( INT32 iBullet ) // decrement is scaled down depending on how fast the bullet is (effective range) pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); } - else if ( (pBullet->usFlags & BULLET_FLAG_FLAME) && ( pBullet->iLoop > pBullet->iRange ) ) + else if ( (pBullet->usFlags & (BULLET_FLAG_FLAME|BULLET_FLAG_WHITESMOKE) ) && ( pBullet->iLoop > pBullet->iRange ) ) { pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); } diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index 08acc2de..86e4c798 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -2459,6 +2459,13 @@ BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLE } } + if ( gpWorldLevelData[pSoldier->sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) + { + { + pExplosive = &( Explosive[Item[GetFirstExplosiveOfType( EXPLOSV_SMOKE_FIRERETARDANT )].ubClassIndex] ); + } + } + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Overhead pSoldier->flags.fHitByGasFlags: %d", pSoldier->flags.fHitByGasFlags ); //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Overhead pExplosive: %d", pExplosive->ubType ); diff --git a/Tactical/bullets.cpp b/Tactical/bullets.cpp index 3e376e3b..e9b8fda9 100644 --- a/Tactical/bullets.cpp +++ b/Tactical/bullets.cpp @@ -294,7 +294,7 @@ void UpdateBullets( ) { // ALRIGHTY, CHECK WHAT TYPE OF BULLET WE ARE - if ( gBullets[ uiCount ].usFlags & ( BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_KNIFE | BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME /*| BULLET_FLAG_TRACER*/ ) ) + if ( gBullets[ uiCount ].usFlags & ( BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_KNIFE | BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_WHITESMOKE /*| BULLET_FLAG_TRACER*/ ) ) { } else @@ -350,7 +350,7 @@ void UpdateBullets( ) } } // Are we a missle? - else if ( gBullets[ uiCount ].usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT ) ) + else if ( gBullets[ uiCount ].usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_WHITESMOKE | BULLET_FLAG_CREATURE_SPIT ) ) { } /* @@ -474,7 +474,7 @@ void AddMissileTrail( BULLET *pBullet, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT q ANITILE_PARAMS AniParams; // If we are a small missle, don't show - if ( pBullet->usFlags & ( BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER*/ ) ) + if ( pBullet->usFlags & ( BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_WHITESMOKE /*| BULLET_FLAG_TRACER*/ ) ) { if ( pBullet->iLoop < 5 ) { @@ -532,6 +532,11 @@ void AddMissileTrail( BULLET *pBullet, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT q strcpy( AniParams.zCachedFile, "TILECACHE\\FLMTHR2.STI" ); AniParams.sDelay = (INT16)( 100 ); } + else if ( pBullet->usFlags & BULLET_FLAG_WHITESMOKE ) + { + strcpy( AniParams.zCachedFile, "TILECACHE\\white_smoke_trail.sti" ); + AniParams.sDelay = (INT16)( 100 ); + } //else if ( pBullet->usFlags & ( BULLET_FLAG_TRACER ) ) // HEADROCK HAM B2.5: Created new bullet flag that tells us whether this specific bullet is a tracer. // The condition now reads that flag and creates a lightshow only for tracer bullets. This flag is only diff --git a/TacticalAI/AIUtils.cpp b/TacticalAI/AIUtils.cpp index d93d3bd2..281aa5da 100644 --- a/TacticalAI/AIUtils.cpp +++ b/TacticalAI/AIUtils.cpp @@ -2261,7 +2261,7 @@ BOOLEAN InWaterGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo ) BOOLEAN InGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo ) { // smoke - if ( gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_SIGNAL_SMOKE | MAPELEMENT_EXT_DEBRIS_SMOKE) ) + if ( gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_SIGNAL_SMOKE | MAPELEMENT_EXT_DEBRIS_SMOKE | MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) ) return TRUE; return InGas(pSoldier,sGridNo); diff --git a/TileEngine/Explosion Control.cpp b/TileEngine/Explosion Control.cpp index e23731c1..2d26a07c 100644 --- a/TileEngine/Explosion Control.cpp +++ b/TileEngine/Explosion Control.cpp @@ -2001,7 +2001,7 @@ BOOLEAN DishOutGasDamage( SOLDIERTYPE * pSoldier, EXPLOSIVETYPE * pExplosive, IN } } - else if ( pExplosive->ubType == EXPLOSV_SMOKE || pExplosive->ubType == EXPLOSV_SMOKE_DEBRIS )//dnl ch40 200909 + else if ( pExplosive->ubType == EXPLOSV_SMOKE || pExplosive->ubType == EXPLOSV_SMOKE_DEBRIS | pExplosive->ubType == EXPLOSV_SMOKE_FIRERETARDANT )//dnl ch40 200909 { // robots are unaffected by smoke if( AM_A_ROBOT(pSoldier) ) @@ -2108,6 +2108,7 @@ BOOLEAN DishOutGasDamage( SOLDIERTYPE * pSoldier, EXPLOSIVETYPE * pExplosive, IN break; case EXPLOSV_SMOKE://dnl ch40 200909 case EXPLOSV_SMOKE_DEBRIS: + case EXPLOSV_SMOKE_FIRERETARDANT: pSoldier->flags.fHitByGasFlags |= HIT_BY_SMOKEGAS; break; default: @@ -2262,6 +2263,12 @@ BOOLEAN ExpAffect( INT32 sBombGridNo, INT32 sGridNo, UINT32 uiDist, UINT16 usIte bSmokeEffectType = DEBRIS_SMOKE_EFFECT; fBlastEffect = FALSE; break; + + case EXPLOSV_SMOKE_FIRERETARDANT: + fSmokeEffect = TRUE; + bSmokeEffectType = FIRERETARDANT_SMOKE_EFFECT; + fBlastEffect = FALSE; + break; } } @@ -2464,6 +2471,15 @@ BOOLEAN ExpAffect( INT32 sBombGridNo, INT32 sGridNo, UINT32 uiDist, UINT16 usIte } else if ( fSmokeEffect ) { + // Flugente: if adding fire retardant, remove fire + if ( pExplosive->ubType == EXPLOSV_SMOKE_FIRERETARDANT ) + { + if ( gpWorldLevelData[sGridNo].ubExtFlags[bLevel] & MAPELEMENT_EXT_BURNABLEGAS ) + { + RemoveSmokeEffectFromTile( sGridNo, bLevel ); + } + } + // If tear gar, determine turns to spread..... if ( sSubsequent == ERASE_SPREAD_EFFECT ) { @@ -2945,7 +2961,15 @@ void SpreadEffect( INT32 sGridNo, UINT8 ubRadius, UINT16 usItem, UINT8 ubOwner, gfMPDebugOutputRandoms = true; #endif } - + + // Flugente: if tile has a fire retardant effect, don't create new fire + if ( Explosive[Item[usItem].ubClassIndex].ubType == EXPLOSV_BURNABLEGAS ) + { + if ( gpWorldLevelData[sGridNo].ubExtFlags[bLevel] & MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) + { + return; + } + } INT32 uiNewSpot, uiTempSpot, uiBranchSpot, cnt, branchCnt; INT32 uiTempRange, ubBranchRange; @@ -2965,7 +2989,7 @@ void SpreadEffect( INT32 sGridNo, UINT8 ubRadius, UINT16 usItem, UINT8 ubOwner, case EXPLOSV_CREATUREGAS: case EXPLOSV_SIGNAL_SMOKE: case EXPLOSV_SMOKE_DEBRIS: - + case EXPLOSV_SMOKE_FIRERETARDANT: fSmokeEffect = TRUE; break; } diff --git a/TileEngine/SmokeEffects.cpp b/TileEngine/SmokeEffects.cpp index 5f3b5d08..798d8488 100644 --- a/TileEngine/SmokeEffects.cpp +++ b/TileEngine/SmokeEffects.cpp @@ -137,6 +137,10 @@ INT8 FromWorldFlagsToSmokeType( UINT16 ubWorldFlags ) { return(DEBRIS_SMOKE_EFFECT); } + else if ( ubWorldFlags & MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) + { + return FIRERETARDANT_SMOKE_EFFECT; + } return(NO_SMOKE_EFFECT); } @@ -180,6 +184,10 @@ UINT16 FromSmokeTypeToWorldFlags( INT8 bType ) return(MAPELEMENT_EXT_DEBRIS_SMOKE); break; + case FIRERETARDANT_SMOKE_EFFECT: + return MAPELEMENT_EXT_FIRERETARDANT_SMOKE; + break; + default: return( 0 ); @@ -288,6 +296,10 @@ INT32 NewSmokeEffect( INT32 sGridNo, UINT16 usItem, INT8 bLevel, UINT8 ubOwner, case EXPLOSV_SMOKE_DEBRIS: bSmokeEffectType = DEBRIS_SMOKE_EFFECT; break; + + case EXPLOSV_SMOKE_FIRERETARDANT: + bSmokeEffectType = FIRERETARDANT_SMOKE_EFFECT; + break; } pSmoke->ubDuration = (UINT8)Explosive[ Item[ usItem ].ubClassIndex ].ubDuration; @@ -395,6 +407,9 @@ INT32 NewSmokeEffect(INT32 sGridNo, UINT16 usItem, INT8 bLevel, UINT8 ubOwner, B case EXPLOSV_SMOKE_DEBRIS: bSmokeEffectType = DEBRIS_SMOKE_EFFECT; break; + case EXPLOSV_SMOKE_FIRERETARDANT: + bSmokeEffectType = FIRERETARDANT_SMOKE_EFFECT; + break; } // sevenfm: use custom duration/radius @@ -607,59 +622,19 @@ void AddSmokeEffectToTile( INT32 iSmokeEffectID, INT8 bType, INT32 sGridNo, INT8 break; case CREATURE_SMOKE_EFFECT: - - if ( !( gGameSettings.fOptions[ TOPTION_ANIMATE_SMOKE ] ) ) - { - strcpy( AniParams.zCachedFile, "TILECACHE\\spit_gas.STI" ); - } - else - { - if ( fDissipating ) - { - strcpy( AniParams.zCachedFile, "TILECACHE\\spit_gas.STI" ); - } - else - { - strcpy( AniParams.zCachedFile, "TILECACHE\\spit_gas.STI" ); - } - } + strcpy( AniParams.zCachedFile, "TILECACHE\\spit_gas.STI" ); break; case SIGNAL_SMOKE_EFFECT: - - if ( !( gGameSettings.fOptions[ TOPTION_ANIMATE_SMOKE ] ) ) - { - strcpy( AniParams.zCachedFile, "TILECACHE\\signal_gas.STI" ); - } - else - { - if ( fDissipating ) - { - strcpy( AniParams.zCachedFile, "TILECACHE\\signal_gas.STI" ); - } - else - { - strcpy( AniParams.zCachedFile, "TILECACHE\\signal_gas.STI" ); - } - } + strcpy( AniParams.zCachedFile, "TILECACHE\\signal_gas.STI" ); break; case DEBRIS_SMOKE_EFFECT: - if ( !(gGameSettings.fOptions[TOPTION_ANIMATE_SMOKE]) ) - { - strcpy( AniParams.zCachedFile, "TILECACHE\\debris_smoke.STI" ); - } - else - { - if ( fDissipating ) - { - strcpy( AniParams.zCachedFile, "TILECACHE\\debris_smoke.STI" ); - } - else - { - strcpy( AniParams.zCachedFile, "TILECACHE\\debris_smoke.STI" ); - } - } + strcpy( AniParams.zCachedFile, "TILECACHE\\debris_smoke.STI" ); + break; + + case FIRERETARDANT_SMOKE_EFFECT: + strcpy( AniParams.zCachedFile, "TILECACHE\\white_smoke.STI" ); break; } @@ -769,6 +744,15 @@ void DecaySmokeEffects( UINT32 uiTime ) } } + // Flugente: if tile has a fire retardant effect, don't create new fire + if ( Explosive[Item[pSmoke->usItem].ubClassIndex].ubType == EXPLOSV_BURNABLEGAS ) + { + if ( gpWorldLevelData[pSmoke->sGridNo].ubExtFlags[bLevel] & MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) + { + pSmoke->bAge = pSmoke->ubDuration + 1; + } + } + if ( fUpdate ) { pSmoke->uiTimeOfLastUpdate = uiTime; diff --git a/TileEngine/SmokeEffects.h b/TileEngine/SmokeEffects.h index c32f2cba..996a40d6 100644 --- a/TileEngine/SmokeEffects.h +++ b/TileEngine/SmokeEffects.h @@ -13,6 +13,7 @@ enum BURNABLEGAS_SMOKE_EFFECT, SIGNAL_SMOKE_EFFECT, // added by Flugente for artillery DEBRIS_SMOKE_EFFECT, // added by Flugente for collapsing roofs + FIRERETARDANT_SMOKE_EFFECT, // added by Flugente for fire extinguishers }; #define SMOKE_EFFECT_INDOORS 0x01 diff --git a/TileEngine/Tile Animation.cpp b/TileEngine/Tile Animation.cpp index 60b3e63b..7bc6a31d 100644 --- a/TileEngine/Tile Animation.cpp +++ b/TileEngine/Tile Animation.cpp @@ -560,8 +560,19 @@ void UpdateAniTiles( ) ubExpType = Explosive[ Item[ (UINT16)pNode->uiUserData ].ubClassIndex ].ubType; + // Flugente: if tile has a fire retardant effect, don't create new fire + if ( ubExpType == EXPLOSV_BURNABLEGAS ) + { + if ( gpWorldLevelData[pNode->sGridNo].ubExtFlags[gExplosionData[pNode->uiUserData3].Params.bLevel] & MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) + { + // don't add fire + return; + } + } + if ( ubExpType == EXPLOSV_TEARGAS || ubExpType == EXPLOSV_MUSTGAS || - ubExpType == EXPLOSV_SMOKE || ubExpType == EXPLOSV_BURNABLEGAS || ubExpType == EXPLOSV_SIGNAL_SMOKE || ubExpType == EXPLOSV_SMOKE_DEBRIS || ubExpType == EXPLOSV_CREATUREGAS) + ubExpType == EXPLOSV_SMOKE || ubExpType == EXPLOSV_BURNABLEGAS || ubExpType == EXPLOSV_SIGNAL_SMOKE || ubExpType == EXPLOSV_SMOKE_DEBRIS || ubExpType == EXPLOSV_CREATUREGAS || + ubExpType == EXPLOSV_SMOKE_FIRERETARDANT ) { // Do sound.... // PlayJA2Sample( AIR_ESCAPING_1, RATE_11025, SoundVolume( HIGHVOLUME, pNode->sGridNo ), 1, SoundDir( pNode->sGridNo ) ); diff --git a/TileEngine/worlddef.h b/TileEngine/worlddef.h index b956ed14..0d60208e 100644 --- a/TileEngine/worlddef.h +++ b/TileEngine/worlddef.h @@ -133,12 +133,13 @@ class SOLDIERTYPE; #define MAPELEMENT_EXT_CLIMBPOINT 0x0200 //0x200 #define MAPELEMENT_EXT_SIGNAL_SMOKE 0x0400 //0x400 // added by Flugente #define MAPELEMENT_EXT_DEBRIS_SMOKE 0x0800 //0x800 // added by Flugente +#define MAPELEMENT_EXT_FIRERETARDANT_SMOKE 0x1000 //0x800 // added by Flugente #define FIRST_LEVEL 0 #define SECOND_LEVEL 1 //#define ANY_SMOKE_EFFECT ( MAPELEMENT_EXT_CREATUREGAS | MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS ) -#define ANY_SMOKE_EFFECT ( MAPELEMENT_EXT_CREATUREGAS | MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS | MAPELEMENT_EXT_BURNABLEGAS | MAPELEMENT_EXT_SIGNAL_SMOKE | MAPELEMENT_EXT_DEBRIS_SMOKE ) +#define ANY_SMOKE_EFFECT ( MAPELEMENT_EXT_CREATUREGAS | MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS | MAPELEMENT_EXT_BURNABLEGAS | MAPELEMENT_EXT_SIGNAL_SMOKE | MAPELEMENT_EXT_DEBRIS_SMOKE | MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) // WDS - Clean up inventory handling diff --git a/Utils/XML_Items.cpp b/Utils/XML_Items.cpp index ff8c850d..e2591279 100644 --- a/Utils/XML_Items.cpp +++ b/Utils/XML_Items.cpp @@ -298,6 +298,7 @@ itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **at strcmp(name, "bloodbag" ) == 0 || strcmp(name, "emptybloodbag" ) == 0 || strcmp(name, "medicalsplint" ) == 0 || + strcmp(name, "fireextinguisher" ) == 0 || strcmp(name, "sFireResistance" ) == 0 || strcmp(name, "usAdministrationModifier" ) == 0)) { @@ -1543,6 +1544,13 @@ itemEndElementHandle(void *userData, const XML_Char *name) if ( (BOOLEAN)atol( pData->szCharData ) ) pData->curItem.usItemFlag |= MEDICAL_SPLINT; } + else if ( strcmp( name, "fireextinguisher" ) == 0 ) + { + pData->curElement = ELEMENT; + + if ( (BOOLEAN)atol( pData->szCharData ) ) + pData->curItem.usItemFlag |= FIREEXTINGUISHER; + } else if ( strcmp( name, "sFireResistance" ) == 0 ) { pData->curElement = ELEMENT; @@ -2192,6 +2200,7 @@ BOOLEAN WriteItemStats() if ( HasItemFlag( cnt, BLOOD_BAG) ) FilePrintf( hFile, "\t\t%d\r\n", 1 ); if ( HasItemFlag( cnt, EMPTY_BLOOD_BAG ) ) FilePrintf( hFile, "\t\t%d\r\n", 1 ); if ( HasItemFlag( cnt, MEDICAL_SPLINT ) ) FilePrintf( hFile, "\t\t%d\r\n", 1 ); + if ( HasItemFlag( cnt, FIREEXTINGUISHER ) ) FilePrintf( hFile, "\t\t%d\r\n", 1 ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].usRiotShieldStrength ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].usRiotShieldGraphic );