diff --git a/GameSettings.cpp b/GameSettings.cpp
index c2a835eb6..1d7d4d0e7 100644
--- a/GameSettings.cpp
+++ b/GameSettings.cpp
@@ -1346,6 +1346,7 @@ void LoadGameExternalOptions()
gGameExternalOptions.fZombieCanClimb = iniReader.ReadBoolean("Tactical Zombie Settings", "ZOMBIE_CAN_CLIMB", TRUE);
gGameExternalOptions.fZombieExplodingCivs = iniReader.ReadBoolean("Tactical Zombie Settings", "ZOMBIE_EXPLODING_CIVS", FALSE);
gGameExternalOptions.sEnemyZombieDamageResistance = iniReader.ReadInteger("Tactical Zombie Settings", "ZOMBIE_DAMAGE_RESISTANCE", 0, -50, 95);
+ gGameExternalOptions.sEnemyZombieBreathDamageResistance = iniReader.ReadInteger("Tactical Zombie Settings", "ZOMBIE_BREATH_DAMAGE_RESISTANCE", 0, -50, 95);
gGameExternalOptions.fZombieOnlyHeadshotsWork = iniReader.ReadBoolean("Tactical Zombie Settings", "ZOMBIE_ONLY_HEADSHOTS_WORK", FALSE);
gGameExternalOptions.sZombieDifficultyLevel = iniReader.ReadInteger("Tactical Zombie Settings", "ZOMBIE_DIFFICULTY_LEVEL", 2, 1, 4);
gGameExternalOptions.fZombieRiseWithArmour = iniReader.ReadBoolean("Tactical Zombie Settings", "ZOMBIE_RISE_WITH_ARMOUR", TRUE);
@@ -2283,6 +2284,8 @@ void LoadGameAPBPConstants()
APBPConstants[AP_JUMPWALL] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_JUMPOFFWALL",40),40);
APBPConstants[AP_JUMPOFFWALL] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_JUMPWALL",24),24);
+ APBPConstants[AP_FORTIFICATION] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_FORTIFICATION",80),80);
+
SetupMaxActionPointsAnimation();
#undef ReadInteger
}
diff --git a/GameSettings.h b/GameSettings.h
index 8d02dd859..6086fc5bb 100644
--- a/GameSettings.h
+++ b/GameSettings.h
@@ -372,6 +372,7 @@ typedef struct
BOOLEAN fZombieCanClimb;
BOOLEAN fZombieExplodingCivs;
INT8 sEnemyZombieDamageResistance;
+ INT8 sEnemyZombieBreathDamageResistance;
BOOLEAN fZombieOnlyHeadshotsWork;
INT8 sZombieDifficultyLevel;
BOOLEAN fZombieRiseWithArmour;
diff --git a/Init.h b/Init.h
index 4b8af54c3..bb88e4be5 100644
--- a/Init.h
+++ b/Init.h
@@ -197,6 +197,7 @@ BP_JUMPOFFWALL,
BP_JUMPWALL,
AP_JUMPWALL,
AP_JUMPOFFWALL,
+AP_FORTIFICATION,
TOTAL_APBP_VALUES
};
#endif
diff --git a/Tactical/Handle Items.cpp b/Tactical/Handle Items.cpp
index 0a2cb129e..4045f0759 100644
--- a/Tactical/Handle Items.cpp
+++ b/Tactical/Handle Items.cpp
@@ -1120,6 +1120,80 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa
}
}
+ // Flugente: sandbag stuff
+ if ( HasItemFlag(usHandItem, (EMPTY_SANDBAG|FULL_SANDBAG|SHOVEL|CONCERTINA)) )
+ {
+ // if we have an empty sandbag in our hands, we also need to have a shovel in our second hand, otherwise we can't fill it
+ if ( HasItemFlag(usHandItem, (EMPTY_SANDBAG)) )
+ {
+ // check if we have a shovel in our second hand
+ OBJECTTYPE* pShovelObj = &(pSoldier->inv[SECONDHANDPOS]);
+
+ if ( !pShovelObj || !(pShovelObj->exists()) || !HasItemFlag(pSoldier->inv[ SECONDHANDPOS ].usItem, (SHOVEL)) )
+ {
+ return( ITEM_HANDLE_REFUSAL );
+ }
+ }
+
+ // if we have a shovel in our hands, the targetted gridno must be a fortification (debris will do for this check)
+ if ( HasItemFlag(usHandItem, (SHOVEL)) )
+ {
+ STRUCTURE* pStruct = FindStructure(sGridNo, STRUCTURE_GENERIC);
+
+ if ( !pStruct )
+ {
+ return( ITEM_HANDLE_REFUSAL );
+ }
+ }
+
+ sActionGridNo = FindAdjacentGridEx( pSoldier, sGridNo, &ubDirection, &sAdjustedGridNo, TRUE, FALSE );
+
+ if ( sActionGridNo != -1 )
+ {
+ // Calculate AP costs...
+ sAPCost = GetAPsToBuildFortification( pSoldier, sActionGridNo );
+ sAPCost += PlotPath( pSoldier, sActionGridNo, NO_COPYROUTE, FALSE, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints);
+
+ if ( EnoughPoints( pSoldier, sAPCost, 0, fFromUI ) )
+ {
+ // CHECK IF WE ARE AT THIS GRIDNO NOW
+ if ( pSoldier->sGridNo != sActionGridNo )
+ {
+ // SEND PENDING ACTION
+ pSoldier->aiData.ubPendingAction = MERC_BUILD_FORTIFICATION;
+ pSoldier->aiData.sPendingActionData2 = sAdjustedGridNo;
+ pSoldier->aiData.bPendingActionData3 = ubDirection;
+ pSoldier->aiData.ubPendingActionAnimCount = 0;
+
+ // WALK UP TO DEST FIRST
+ pSoldier->EVENT_InternalGetNewSoldierPath( sActionGridNo, pSoldier->usUIMovementMode, FALSE, TRUE );
+ }
+ else
+ {
+ pSoldier->EVENT_SoldierBuildStructure( sAdjustedGridNo, ubDirection );
+ }
+
+ // OK, set UI
+ SetUIBusy( pSoldier->ubID );
+
+ if ( fFromUI )
+ {
+ guiPendingOverrideEvent = A_CHANGE_TO_MOVE;
+ }
+
+ return( ITEM_HANDLE_OK );
+ }
+ else
+ {
+ return( ITEM_HANDLE_NOAPS );
+ }
+ }
+ else
+ {
+ return( ITEM_HANDLE_CANNOT_GETTO_LOCATION );
+ }
+ }
+
if ( Item[usHandItem].canandstring )
{
STRUCTURE *pStructure;
@@ -5907,3 +5981,214 @@ void SoldierStealItemFromSoldier( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent,
gsTempGridNo = sGridNo;
SetCustomizableTimerCallbackAndDelay( 1000, CheckForPickedOwnership, TRUE );
}
+
+extern UINT8 NumEnemiesInAnySector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ );
+
+BOOLEAN BuildFortification( UINT32 flag )
+{
+ INT32 sGridNo;
+ UINT32 fHeadType;
+ UINT16 usUseIndex;
+ UINT16 usUseObjIndex = 0;
+ INT32 iRandSelIndex = 1;
+ BOOLEAN fOkayToAdd;
+ UINT8 ubDirection;
+
+ if ( gusSelectedSoldier == NOBODY )
+ return FALSE;
+
+ if( (gTacticalStatus.uiFlags & INCOMBAT) && (gTacticalStatus.uiFlags & TURNBASED) )
+ {
+ return FALSE;
+ }
+
+ /* // comment this in to forbid building while enemies are around
+ if( gWorldSectorX != -1 && gWorldSectorY != -1 && gWorldSectorX != 0 && gWorldSectorY != 0 &&
+ NumEnemiesInAnySector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) > 0 )
+ {
+ ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Cannot build while enemies are in this sector" );
+ return FALSE;
+ }*/
+
+ if( gbWorldSectorZ > 0 || gsInterfaceLevel > 0)
+ {
+ return FALSE;
+ }
+
+ GetMouseMapPos( &sGridNo );
+
+ if( InARoom( sGridNo, NULL ) )
+ return FALSE;
+
+ INT8 bOverTerrainType = GetTerrainType( sGridNo );
+ if( bOverTerrainType == MED_WATER || bOverTerrainType == DEEP_WATER || bOverTerrainType == LOW_WATER )
+ return FALSE;
+
+ UINT16 CurrentStruct = NO_TILE;
+
+ if ( sGridNo < 0x80000000 )
+ {
+ ubDirection = MercPtrs[ gusSelectedSoldier ]->ubDirection;
+
+ if ( (flag & CONCERTINA) != 0 )
+ {
+ // concertina wire
+ switch ( ubDirection )
+ {
+ case NORTH:
+ case SOUTH:
+ usUseIndex = 2 + 2*Random(2);
+ break;
+ case WEST:
+ case EAST:
+ usUseIndex = 3 + 2*Random(2);
+ break;
+ case NORTHEAST:
+ usUseIndex = 9;
+ break;
+ case SOUTHWEST:
+ usUseIndex = 8;
+ break;
+ case NORTHWEST:
+ usUseIndex = 7;
+ break;
+ case SOUTHEAST:
+ default:
+ usUseIndex = 6;
+ break;
+ }
+ }
+ else
+ {
+ // sandbags
+ switch ( ubDirection )
+ {
+ case NORTH:
+ case SOUTH:
+ usUseIndex = 3 + Random(2);
+ break;
+ case WEST:
+ case EAST:
+ usUseIndex = 8 + Random(2);
+ break;
+ case NORTHEAST:
+ case SOUTHWEST:
+ case NORTHWEST:
+ case SOUTHEAST:
+ default:
+ usUseIndex = 5;
+ break;
+ }
+
+ //usUseObjIndex = (UINT16)THIRDOSTRUCT;//SelOStructs2[ iRandSelIndex ].uiObject;
+ }
+
+ // search wether structure exists in the current tilesets. If not, well, too bad
+ UINT32 uiType = 0;
+
+ for(uiType = 0; uiType < giNumberOfTileTypes; ++uiType)
+ {
+ if( gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiType ][0] )
+ {
+ if( (flag & CONCERTINA) != 0 )
+ {
+ if ( (_strnicmp(gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiType ], "spot_1.sti", 10) == 0) )
+ {
+ usUseObjIndex = uiType;
+ break;
+ }
+ }
+ else if( (_strnicmp(gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiType ], "sandbag.sti", 11) == 0) )
+ {
+ usUseObjIndex = uiType;
+ break;
+ }
+ }
+ }
+
+ if ( !usUseObjIndex )
+ {
+ ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"The selected barricade cannot be built in this sector" );
+ return FALSE;
+ }
+
+ // Check with Structure Database (aka ODB) if we can put the object here!
+ fOkayToAdd = OkayToAddStructureToWorld( sGridNo, 0, gTileDatabase[ (gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) ].pDBStructureRef, INVALID_STRUCTURE_ID );
+ if ( fOkayToAdd || (gTileDatabase[ (gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) ].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
+ RemoveStruct( sGridNo, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) );//dnl
+ // Actual structure info is added by the functions below
+ AddStructToHead( sGridNo, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) );
+ // For now, adjust to shadows by a hard-coded amount,
+
+ // Add mask if in long grass
+ GetLandHeadType( sGridNo, &fHeadType );
+
+ RecompileLocalMovementCosts(sGridNo);
+
+ // Turn off permanent changes....
+ ApplyMapChangesToMapTempFile( FALSE );
+ SetRenderFlags( RENDER_FLAG_FULL );
+
+ return TRUE;
+ }
+ }
+ else if ( CurrentStruct == ERASE_TILE && sGridNo < 0x80000000 )
+ {
+ RemoveAllStructsOfTypeRange( sGridNo, FIRSTOSTRUCT, LASTOSTRUCT );
+ RemoveAllShadowsOfTypeRange( sGridNo, FIRSTSHADOW, LASTSHADOW );
+ }
+
+ return FALSE;
+}
+
+BOOLEAN RemoveFortification( INT32 sGridNo )
+{
+ STRUCTURE* pStruct = FindStructure(sGridNo, STRUCTURE_GENERIC);
+
+ if ( pStruct != NULL )
+ {
+ // Get LEVELNODE for struct and remove!
+ LEVELNODE* pNode = FindLevelNodeBasedOnStructure( pStruct->sGridNo, pStruct );
+
+ if ( pNode )
+ {
+ UINT32 uiTileType = 0;
+ if ( GetTileType( pNode->usIndex, &uiTileType ) )
+ {
+ UINT16 usIndex = pNode->usIndex;
+
+ // Check if we are a sandbag
+ if ( _strnicmp( gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiTileType ], "sandbag.sti", 11) == 0 )
+ {
+ // Remove old graphic
+ ApplyMapChangesToMapTempFile( TRUE );
+
+ RemoveStruct( sGridNo, pNode->usIndex );
+ if ( !GridNoIndoors( sGridNo ) && gTileDatabase[ usIndex ].uiFlags & HAS_SHADOW_BUDDY && gTileDatabase[ usIndex ].sBuddyNum != -1 )
+ {
+ RemoveShadow( sGridNo, gTileDatabase[ usIndex ].sBuddyNum );
+ }
+
+ // Add mask if in long grass
+ UINT32 fHeadType = 0;
+ GetLandHeadType( sGridNo, &fHeadType );
+
+ RecompileLocalMovementCosts(sGridNo);
+
+ // Turn off permanent changes....
+ ApplyMapChangesToMapTempFile( FALSE );
+ SetRenderFlags( RENDER_FLAG_FULL );
+
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
diff --git a/Tactical/Handle Items.h b/Tactical/Handle Items.h
index f6d6f25f3..f5960f62f 100644
--- a/Tactical/Handle Items.h
+++ b/Tactical/Handle Items.h
@@ -175,6 +175,9 @@ UINT8 StealItems(SOLDIERTYPE* pSoldier,SOLDIERTYPE* pOpponent, UINT8* ubIndexRet
BOOLEAN MarblesExistAtLocation( INT32 sGridNo, UINT8 ubLevel, INT32 * piItemIndex );
+BOOLEAN BuildFortification( UINT32 flag = FULL_SANDBAG ); // Flugente: build a structure, return true if sucessful
+BOOLEAN RemoveFortification( INT32 sGridNo );
+
extern ITEM_POOL *gpItemPool;//dnl ch26 210909
#endif
\ No newline at end of file
diff --git a/Tactical/Handle UI.cpp b/Tactical/Handle UI.cpp
index ff6cc2ce7..17895b325 100644
--- a/Tactical/Handle UI.cpp
+++ b/Tactical/Handle UI.cpp
@@ -4117,6 +4117,24 @@ INT8 DrawUIMovementPath( SOLDIERTYPE *pSoldier, INT32 usMapPos, UINT32 uiFlags )
gsUIHandleShowMoveGridLocation = sActionGridNo;
}
}
+ else if ( uiFlags == MOVEUI_TARGET_FORTIFICATION )
+ {
+ sActionGridNo = FindAdjacentGridEx( pSoldier, usMapPos, &ubDirection, NULL, FALSE, TRUE );
+ if ( sActionGridNo == -1 )
+ {
+ sActionGridNo = usMapPos;
+ }
+
+ sAPCost = GetAPsToBuildFortification( pSoldier, sActionGridNo );
+
+ sAPCost += UIPlotPath( pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints);
+
+ if ( sActionGridNo != pSoldier->sGridNo )
+ {
+ gfUIHandleShowMoveGrid = TRUE;
+ gsUIHandleShowMoveGridLocation = sActionGridNo;
+ }
+ }
else if ( uiFlags == MOVEUI_TARGET_MERCS )
{
INT32 sGotLocation = NOWHERE;
@@ -4423,6 +4441,45 @@ BOOLEAN UIMouseOnValidAttackLocation( SOLDIERTYPE *pSoldier )
}
}
+ if ( ubItemCursor == FORTICURS )
+ {
+ if ( gfUIFullTargetFound )
+ {
+ usMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo;
+ }
+
+ if ( pSoldier->pathing.bLevel == 0 )
+ {
+ if ( IsFortificationPossibleAtGridNo( usMapPos, NULL ) )
+ {
+ return( TRUE );
+ }
+
+ if ( HasItemFlag( (&(pSoldier->inv[HANDPOS]))->usItem, (EMPTY_SANDBAG)) )
+ {
+ // check if we have a shovel in our second hand
+ OBJECTTYPE* pShovelObj = &(pSoldier->inv[SECONDHANDPOS]);
+
+ if ( !pShovelObj || !(pShovelObj->exists()) || !HasItemFlag(pSoldier->inv[ SECONDHANDPOS ].usItem, (SHOVEL)) )
+ {
+ return( TRUE );
+ }
+ }
+
+ if ( HasItemFlag( (&(pSoldier->inv[HANDPOS]))->usItem, (SHOVEL)) )
+ {
+ STRUCTURE* pStruct = FindStructure(usMapPos, STRUCTURE_GENERIC);
+
+ if ( pStruct )
+ {
+ return( TRUE );
+ }
+ }
+ }
+
+ return( FALSE );
+ }
+
if ( ubItemCursor == BOMBCURS )
{
if ( usMapPos == pSoldier->sGridNo )
diff --git a/Tactical/Handle UI.h b/Tactical/Handle UI.h
index f71f5c46e..3580f9281 100644
--- a/Tactical/Handle UI.h
+++ b/Tactical/Handle UI.h
@@ -29,6 +29,7 @@
#define MOVEUI_TARGET_JAR 10
#define MOVEUI_TARGET_CAN 11
#define MOVEUI_TARGET_REFUEL 12
+#define MOVEUI_TARGET_FORTIFICATION 13
#define MOVEUI_RETURN_ON_TARGET_MERC 1
diff --git a/Tactical/Interface Cursors.cpp b/Tactical/Interface Cursors.cpp
index 0f1de7f47..e1c92a753 100644
--- a/Tactical/Interface Cursors.cpp
+++ b/Tactical/Interface Cursors.cpp
@@ -212,6 +212,9 @@ UICursor gUICursors[ NUM_UI_CURSORS ] =
REFUEL_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_FUEL, 0,
REFUEL_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_FUEL_RED, 0,
+ FORTIFICATION_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_FORTIFICATION, 0,
+ FORTIFICATION_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_FORTIFICATION_RED, 0,
+
};
diff --git a/Tactical/Interface Cursors.h b/Tactical/Interface Cursors.h
index 599ea2c38..f15243617 100644
--- a/Tactical/Interface Cursors.h
+++ b/Tactical/Interface Cursors.h
@@ -186,6 +186,9 @@ typedef enum
REFUEL_GREY_UICURSOR,
REFUEL_RED_UICURSOR,
+ FORTIFICATION_GREY_UICURSOR,
+ FORTIFICATION_RED_UICURSOR,
+
NUM_UI_CURSORS
} UICursorDefines;
diff --git a/Tactical/Item Types.h b/Tactical/Item Types.h
index cb72bb062..39b29d65b 100644
--- a/Tactical/Item Types.h
+++ b/Tactical/Item Types.h
@@ -173,6 +173,7 @@ typedef enum ATTACHMENT_SLOT{
#define JARCURS 21
#define TINCANCURS 22
#define REFUELCURS 23
+#define FORTICURS 24
#define CAMERARANGE 10
@@ -708,6 +709,50 @@ extern OBJECTTYPE gTempObject;
#define PLAYER_NET_4_LVL_4 0x80000000 //2147483648
// ----------------------------------------------------------------
+// -------- added by Flugente: various item flags --------
+// flags used for various item properties (easier than adding 32 differently named variables). DO NOT CHANGE THEM, UNLESS YOU KNOW WHAT YOU ARE DOING!!!
+// note that these should not be used to determine what kind of an attachment an item is, that is determined by attachmentclass and the AC_xxx flags above
+#define EMPTY_SANDBAG 0x00000001 //1
+#define FULL_SANDBAG 0x00000002 //2
+#define SHOVEL 0x00000004 //4
+#define CONCERTINA 0x00000008 //8
+
+/*#define WH40K_POWER_ARMOR 0x00000010 //16
+#define WH40K_POWER_PACK 0x00000020 //32
+#define WH40K_JUMPPACK 0x00000040 //64
+#define WH40K_DISPLACER 0x00000080 //128
+
+#define WH40K_ROSARIUS 0x00000100 //256
+#define WH40K_SEAL 0x00000200 //512
+#define WH40K_POWER_WEAPON 0x00000400 //1024
+#define ENEMY_NET_4_LVL_3 0x00000800 //2048
+
+#define ENEMY_NET_1_LVL_4 0x00001000 //4096
+#define ENEMY_NET_2_LVL_4 0x00002000 //8192
+#define ENEMY_NET_3_LVL_4 0x00004000 //16384
+#define ENEMY_NET_4_LVL_4 0x00008000 //32768
+
+#define PLAYER_NET_1_LVL_1 0x00010000 //65536
+#define PLAYER_NET_2_LVL_1 0x00020000 //131072
+#define PLAYER_NET_3_LVL_1 0x00040000 //262144
+#define PLAYER_NET_4_LVL_1 0x00080000 //524288
+
+#define PLAYER_NET_1_LVL_2 0x00100000 //1048576
+#define PLAYER_NET_2_LVL_2 0x00200000 //2097152
+#define PLAYER_NET_3_LVL_2 0x00400000 //4194304
+#define PLAYER_NET_4_LVL_2 0x00800000 //8388608
+
+#define PLAYER_NET_1_LVL_3 0x01000000 //16777216
+#define PLAYER_NET_2_LVL_3 0x02000000 //33554432
+#define PLAYER_NET_3_LVL_3 0x04000000 //67108864
+#define PLAYER_NET_4_LVL_3 0x08000000 //134217728
+
+#define PLAYER_NET_1_LVL_4 0x10000000 //268435456
+#define PLAYER_NET_2_LVL_4 0x20000000 //536870912
+#define PLAYER_NET_3_LVL_4 0x40000000 //1073741824
+#define PLAYER_NET_4_LVL_4 0x80000000 //2147483648*/
+// ----------------------------------------------------------------
+
// replaces candamage
//#define ITEM_DAMAGEABLE 0x0001
//// replaces canrepair
@@ -962,6 +1007,8 @@ typedef struct
// Flugente poison system
INT16 bPoisonPercentage;
+ UINT32 usItemFlag; // bitflags to store various item properties (better than introducing 32 BOOLEAN values). If I only had thought of this earlier....
+
} INVTYPE;
// CHRISL: Added new structures to handle LBE gear and the two new XML files that will be needed to deal
diff --git a/Tactical/Items.cpp b/Tactical/Items.cpp
index 471fe1e20..34d5b5c7a 100644
--- a/Tactical/Items.cpp
+++ b/Tactical/Items.cpp
@@ -13938,3 +13938,9 @@ void CheckBombSpecifics( OBJECTTYPE * pObj, INT8* detonatortype, INT8* setting,
*defusefrequency = (*pObj)[0]->data.bDefuseFrequency;
}
}
+
+// Flugente: check for specific flags
+BOOLEAN HasItemFlag( UINT16 usItem, UINT32 aFlag )
+{
+ return( (Item[usItem].usItemFlag & aFlag) != 0 );
+}
diff --git a/Tactical/Items.h b/Tactical/Items.h
index ca2c700e6..e4f07df2d 100644
--- a/Tactical/Items.h
+++ b/Tactical/Items.h
@@ -462,4 +462,7 @@ UINT64 GetAvailableAttachmentPoint ( OBJECTTYPE * pObject, UINT8 subObject );
// Flugente: check if and how a bomb has been set up
void CheckBombSpecifics( OBJECTTYPE * pObj, INT8* detonatortype, INT8* setting, INT8* defusefrequency );
+// Flugente: check for specific flags
+BOOLEAN HasItemFlag( UINT16 usItem, UINT32 aFlag );
+
#endif
diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp
index f1df4ae11..69f4857d7 100644
--- a/Tactical/Overhead.cpp
+++ b/Tactical/Overhead.cpp
@@ -1649,6 +1649,11 @@ BOOLEAN ExecuteOverhead( )
pSoldier->EVENT_SoldierBeginCutFence( pSoldier->aiData.sPendingActionData2, pSoldier->aiData.bPendingActionData3 );
pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION;
}
+ else if ( pSoldier->aiData.ubPendingAction == MERC_BUILD_FORTIFICATION )
+ {
+ pSoldier->EVENT_SoldierBuildStructure( pSoldier->aiData.sPendingActionData2, pSoldier->aiData.bPendingActionData3 );
+ pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION;
+ }
else if ( pSoldier->aiData.ubPendingAction == MERC_GIVEITEM )
{
pSoldier->EVENT_SoldierBeginGiveItem( );
diff --git a/Tactical/Points.cpp b/Tactical/Points.cpp
index 730b2ab15..b86353c57 100644
--- a/Tactical/Points.cpp
+++ b/Tactical/Points.cpp
@@ -3476,6 +3476,23 @@ INT16 GetAPsToUseCan( SOLDIERTYPE *pSoldier, INT32 usMapPos )
}
+INT16 GetAPsToBuildFortification( SOLDIERTYPE *pSoldier, INT32 usMapPos )
+{
+ INT16 sAPCost = 0;
+
+ sAPCost = PlotPath( pSoldier, usMapPos, NO_COPYROUTE, NO_PLOT, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints );
+
+ // If point cost is zero, return 0
+ if ( sAPCost != 0 )
+ {
+ // ADD APS TO PICKUP
+ sAPCost += APBPConstants[AP_FORTIFICATION];
+ }
+
+ return sAPCost;
+
+}
+
INT16 GetAPsToJumpOver( SOLDIERTYPE *pSoldier )
{
diff --git a/Tactical/Points.h b/Tactical/Points.h
index b210be340..a9be7f803 100644
--- a/Tactical/Points.h
+++ b/Tactical/Points.h
@@ -356,6 +356,8 @@ INT16 GetAPsToUseJar( SOLDIERTYPE *pSoldier, INT32 usMapPos );
INT16 GetAPsToUseCan( SOLDIERTYPE *pSoldier, INT32 usMapPos );
INT16 GetBPsTouseJar( SOLDIERTYPE *pSoldier );
+INT16 GetAPsToBuildFortification( SOLDIERTYPE *pSoldier, INT32 usMapPos ); // added by Flugente
+
INT16 GetAPsToJumpOver( SOLDIERTYPE *pSoldier );
void GetAPChargeForShootOrStabWRTGunRaises( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, BOOLEAN *pfChargeTurning, BOOLEAN *pfChargeRaise );
diff --git a/Tactical/Rotting Corpses.cpp b/Tactical/Rotting Corpses.cpp
index 1b18818e2..ef4c965fa 100644
--- a/Tactical/Rotting Corpses.cpp
+++ b/Tactical/Rotting Corpses.cpp
@@ -2143,6 +2143,8 @@ void RaiseZombies( void )
if ( zombieshaverisen )
{
+ SetRenderFlags( RENDER_FLAG_FULL );
+
#ifdef JA2TESTVERSION
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"A wave of zombies is created");
#endif
diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp
index a84efacd9..4cf684e36 100644
--- a/Tactical/Soldier Control.cpp
+++ b/Tactical/Soldier Control.cpp
@@ -13403,7 +13403,12 @@ INT32 SOLDIERTYPE::GetDamageResistance(BOOLEAN fAutoResolve, BOOLEAN fCalcBreath
else if (this->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0)
resistance += gGameExternalOptions.sEnemyEliteDamageResistance;
else if (IsZombie())
- resistance += gGameExternalOptions.sEnemyZombieDamageResistance;
+ {
+ if ( fCalcBreathLoss )
+ resistance += gGameExternalOptions.sEnemyZombieBreathDamageResistance;
+ else
+ resistance += gGameExternalOptions.sEnemyZombieDamageResistance;
+ }
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -14370,6 +14375,103 @@ void SOLDIERTYPE::EVENT_SoldierBeginAttachCan( INT32 sGridNo, UINT8 ubDirection
}
+void SOLDIERTYPE::EVENT_SoldierBuildStructure( INT32 sGridNo, UINT8 ubDirection )
+{
+ BOOLEAN fSuccess = FALSE;
+ // do checks here...
+ OBJECTTYPE* pObj = &(this->inv[HANDPOS]);
+
+ if ( pObj && pObj->exists() && HasItemFlag(this->inv[ HANDPOS ].usItem, (EMPTY_SANDBAG|FULL_SANDBAG|SHOVEL|CONCERTINA)) )
+ {
+ // CHANGE DIRECTION AND GOTO ANIMATION NOW
+ this->EVENT_SetSoldierDesiredDirection( ubDirection );
+ this->EVENT_SetSoldierDirection( ubDirection );
+
+ if (!is_networked)
+ this->EVENT_InitNewSoldierAnim( CUTTING_FENCE, 0 , FALSE );
+ else
+ this->ChangeSoldierState( CUTTING_FENCE, 0, 0 );
+
+ if ( HasItemFlag(this->inv[ HANDPOS ].usItem, (FULL_SANDBAG|CONCERTINA)) )
+ {
+ // Build the thing
+ if ( BuildFortification( Item[ pObj->usItem ].usItemFlag ) )
+ {
+ // Erase 'material' item from our hand - we 'used' it to build the structure
+ DeleteObj( &(this->inv[HANDPOS]) );
+
+ // we gain a bit of experience...
+ StatChange( this, STRAMT, 4, TRUE );
+ StatChange( this, HEALTHAMT, 2, TRUE );
+
+ fSuccess = TRUE;
+ }
+ }
+ else if ( HasItemFlag(this->inv[ HANDPOS ].usItem, (EMPTY_SANDBAG)) )
+ {
+ INT8 bOverTerrainType = GetTerrainType( sGridNo );
+ if( bOverTerrainType == FLAT_GROUND || bOverTerrainType == DIRT_ROAD || bOverTerrainType == LOW_GRASS )
+ {
+ // check if we have a shovel in our second hand
+ OBJECTTYPE* pShovelObj = &(this->inv[SECONDHANDPOS]);
+
+ if ( pShovelObj && pShovelObj->exists() && HasItemFlag(this->inv[ SECONDHANDPOS ].usItem, (SHOVEL)) )
+ {
+ // test: does there an item that is a filled sandbag exist? (xmls might have changed)
+ UINT16 fullsandbagnr = 1541;
+ if ( HasItemFlag(fullsandbagnr, FULL_SANDBAG) )
+ {
+ // Erase 'material' item from our hand - we 'used' it to build the structure
+ INT8 bObjSlot = HANDPOS;
+
+ CreateItem( fullsandbagnr, 100, &gTempObject );
+
+ SwapObjs( this, bObjSlot, &gTempObject, TRUE );
+
+ // we gain a bit of experience...
+ StatChange( this, STRAMT, 1, TRUE );
+ StatChange( this, HEALTHAMT, 1, TRUE );
+
+ fSuccess = TRUE;
+ }
+ }
+ }
+ }
+ else if ( HasItemFlag(this->inv[ HANDPOS ].usItem, (SHOVEL)) )
+ {
+ // Build the thing
+ if ( RemoveFortification( sGridNo ) )
+ {
+ // test: does there an item that is a filled sandbag exist? (xmls might have changed)
+ UINT16 fullsandbagnr = 1541;
+ if ( HasItemFlag(fullsandbagnr, FULL_SANDBAG) )
+ {
+ // Erase 'material' item from our hand - we 'used' it to build the structure
+ INT8 bObjSlot = HANDPOS;
+
+ CreateItem( fullsandbagnr, 100, &gTempObject );
+
+ // now add a tripwire item to the floor, simulating that activating tripwire deactivates it
+ AddItemToPool( sGridNo, &gTempObject, 1, 0, 0, -1 );
+
+ // we gain a bit of experience...
+ StatChange( this, STRAMT, 3, TRUE );
+ StatChange( this, HEALTHAMT, 2, TRUE );
+
+ fSuccess = TRUE;
+ }
+ }
+ }
+ }
+
+ if ( !fSuccess )
+ {
+ // Say NOTHING quote...
+ this->DoMercBattleSound( BATTLE_SOUND_NOTHING );
+ }
+}
+
+
void SOLDIERTYPE::EVENT_SoldierBeginReloadRobot( INT32 sGridNo, UINT8 ubDirection, UINT8 ubMercSlot )
{
UINT8 ubPerson;
diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h
index 8ceb42fb2..9be10be74 100644
--- a/Tactical/Soldier Control.h
+++ b/Tactical/Soldier Control.h
@@ -220,6 +220,7 @@ enum
MERC_TAKEBLOOD,
MERC_ATTACH_CAN,
MERC_FUEL_VEHICLE,
+ MERC_BUILD_FORTIFICATION,
};
// ENUMERATIONS FOR THROW ACTIONS
@@ -1240,6 +1241,8 @@ public:
void EVENT_SoldierBeginAttachCan( INT32 sGridNo, UINT8 ubDirection );
void EVENT_BeginMercTurn( BOOLEAN fFromRealTime, INT32 iRealTimeCounter );
+ void EVENT_SoldierBuildStructure( INT32 sGridNo, UINT8 ubDirection ); // added by Flugente
+
BOOLEAN EVENT_InternalGetNewSoldierPath( INT32 sDestGridNo, UINT16 usMovementAnim, BOOLEAN fFromUI, BOOLEAN fForceRestart );
void EVENT_InternalSetSoldierDestination( UINT16 usNewDirection, BOOLEAN fFromMove, UINT16 usAnimState );
void EVENT_InternalSetSoldierPosition( FLOAT dNewXPos, FLOAT dNewYPos ,BOOLEAN fUpdateDest, BOOLEAN fUpdateFinalDest, BOOLEAN fForceDelete );
diff --git a/Tactical/Structure Wrap.cpp b/Tactical/Structure Wrap.cpp
index db384fd75..51f1f06b3 100644
--- a/Tactical/Structure Wrap.cpp
+++ b/Tactical/Structure Wrap.cpp
@@ -564,6 +564,22 @@ BOOLEAN IsRefuelableStructAtGridNo( INT32 sGridNo, UINT8 *pubID )
}
+// Flugente: determine wether a fortification can be built on this position
+BOOLEAN IsFortificationPossibleAtGridNo( INT32 sGridNo, UINT8 *pubID )
+{
+ GetMouseMapPos( &sGridNo );
+
+ INT8 bOverTerrainType = GetTerrainType( sGridNo );
+ if( bOverTerrainType == MED_WATER || bOverTerrainType == DEEP_WATER || bOverTerrainType == LOW_WATER )
+ return FALSE;
+
+ STRUCTURE * pStructure = NULL;
+
+ pStructure = FindStructure( sGridNo, (STRUCTURE_OBSTACLE) );
+
+ return( pStructure == NULL );
+}
+
BOOLEAN IsCutWireFenceAtGridNo( INT32 sGridNo )
{
diff --git a/Tactical/Structure Wrap.h b/Tactical/Structure Wrap.h
index d46b1c971..ca2c28b3c 100644
--- a/Tactical/Structure Wrap.h
+++ b/Tactical/Structure Wrap.h
@@ -38,6 +38,7 @@ BOOLEAN IsCutWireFenceAtGridNo( INT32 sGridNo );
BOOLEAN IsRepairableStructAtGridNo( INT32 sGridNo, UINT8 *pubID );
BOOLEAN IsRefuelableStructAtGridNo( INT32 sGridNo, UINT8 *pubID );
+BOOLEAN IsFortificationPossibleAtGridNo( INT32 sGridNo, UINT8 *pubID ); // added by Flugente
BOOLEAN IsRoofPresentAtGridNo( INT32 sGridNo );
diff --git a/Tactical/Turn Based Input.cpp b/Tactical/Turn Based Input.cpp
index 410a697af..f784ffaa0 100644
--- a/Tactical/Turn Based Input.cpp
+++ b/Tactical/Turn Based Input.cpp
@@ -4440,7 +4440,10 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
}
else
{
- SetScopeMode();
+ INT32 sGridNo = 0;
+ GetMouseMapPos( &sGridNo );
+ RemoveFortification( sGridNo );
+ //SetScopeMode();
}
break;
diff --git a/Tactical/UI Cursors.cpp b/Tactical/UI Cursors.cpp
index 7def00e3a..f5a328781 100644
--- a/Tactical/UI Cursors.cpp
+++ b/Tactical/UI Cursors.cpp
@@ -53,6 +53,7 @@ UINT8 HandleRemoteCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivat
UINT8 HandleBombCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags );
UINT8 HandleJarCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
UINT8 HandleTinCanCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
+UINT8 HandleFortificationCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags ); //added by Flugente
extern BOOLEAN HandleCheckForBadChangeToGetThrough( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pTargetSoldier, INT32 sTargetGridNo , INT8 bLevel );
@@ -298,6 +299,11 @@ UINT8 GetProperItemCursor( UINT8 ubSoldierID, UINT16 ubItemIndex, INT32 usMapPos
ubCursorID = HandleRefuelCursor( pSoldier, sTargetGridNo, uiCursorFlags );
break;
+ case FORTICURS:
+
+ ubCursorID = HandleFortificationCursor( pSoldier, sTargetGridNo, uiCursorFlags );
+ break;
+
case INVALIDCURS:
ubCursorID = INVALID_ACTION_UICURSOR;
@@ -2138,6 +2144,45 @@ UINT8 HandleBombCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated
}
}
+UINT8 HandleFortificationCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
+{
+ // DRAW PATH TO GUY
+ HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_FORTIFICATION );
+
+ if ( pSoldier->pathing.bLevel != 0 )
+ return( FORTIFICATION_RED_UICURSOR );
+
+ // if we have an empty sandbag in our hands, we also need to have a shovel in our second hand, otherwise we can't fill it
+ if ( HasItemFlag( (&(pSoldier->inv[HANDPOS]))->usItem, (EMPTY_SANDBAG)) )
+ {
+ // check if we have a shovel in our second hand
+ OBJECTTYPE* pShovelObj = &(pSoldier->inv[SECONDHANDPOS]);
+
+ if ( !pShovelObj || !(pShovelObj->exists()) || !HasItemFlag(pSoldier->inv[ SECONDHANDPOS ].usItem, (SHOVEL)) )
+ {
+ return( FORTIFICATION_RED_UICURSOR );
+ }
+ }
+
+ if ( HasItemFlag( (&(pSoldier->inv[HANDPOS]))->usItem, (SHOVEL)) )
+ {
+ STRUCTURE* pStruct = FindStructure(sGridNo, STRUCTURE_GENERIC);
+
+ if ( pStruct )
+ {
+ return( FORTIFICATION_GREY_UICURSOR );
+ }
+ }
+
+ // can we build something here?
+ if ( IsFortificationPossibleAtGridNo( sGridNo, NULL ) && pSoldier->pathing.bLevel == 0 )
+ {
+ return( FORTIFICATION_GREY_UICURSOR );
+ }
+
+ return( FORTIFICATION_RED_UICURSOR );
+}
+
void HandleEndConfirmCursor( SOLDIERTYPE *pSoldier )
@@ -2596,6 +2641,10 @@ UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier )
}
}
+ // Flugente: cursor for building fortifications
+ if ( HasItemFlag(usInHand, (EMPTY_SANDBAG|FULL_SANDBAG|SHOVEL|CONCERTINA)) )
+ ubCursor = FORTICURS;
+
// Now check our terrain to see if we cannot do the action now...
if ( WaterTooDeepForAttacks( pSoldier->sGridNo) )
{
diff --git a/Utils/Cursors.cpp b/Utils/Cursors.cpp
index 76acd5756..5f224fb1c 100644
--- a/Utils/Cursors.cpp
+++ b/Utils/Cursors.cpp
@@ -118,6 +118,10 @@ CursorFileData CursorFileDatabase[] =
{ "CURSORS\\cur_swit.sti" , FALSE, 0, 0, 0, NULL },
{ "CURSORS\\bullseye.sti" , FALSE, 0, 0, 0, NULL },
{ "CURSORS\\deadleap.sti" , FALSE, 0, 0, 0, NULL },
+
+ { "CURSORS\\hammer.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL }, // Flugente: fortification stuff
+ { "CURSORS\\hammer_r.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL },
+
{ "CURSORS\\can_01.sti" , FALSE, 0, 0, 0, NULL },
{ "CURSORS\\can_02.sti" , FALSE, 0, 0, 0, NULL },
{ "CURSORS\\cur_tagr_ncth.sti" , FALSE, 0, ANIMATED_CURSOR, 7, NULL },
@@ -1178,6 +1182,27 @@ CursorData CursorDatabase[] =
0, 0, 0, 0, 0,
2, CENTER_CURSOR, CENTER_CURSOR , 0, 0 , 0, 0 },
+ /*{ C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR,
+ C_FORTIFICATION , 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0 , 0, 0 },*/
+
+ { C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR,
+ C_FORTIFICATION , 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0 , 0, 0 },
+
+ { C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR,
+ C_FORTIFICATION_RED , 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0 , 0, 0 },
+
{ C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR,
C_FUEL , 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR,
0, 0, 0, 0, 0,
diff --git a/Utils/Cursors.h b/Utils/Cursors.h
index 2dcacae9c..660a44718 100644
--- a/Utils/Cursors.h
+++ b/Utils/Cursors.h
@@ -152,6 +152,10 @@ typedef enum
CURSOR_STRATEGIC_BULLSEYE,
CURSOR_JUMP_OVER,
+
+ CURSOR_FORTIFICATION,
+ CURSOR_FORTIFICATION_RED,
+
CURSOR_FUEL,
CURSOR_FUEL_RED,
@@ -225,6 +229,8 @@ typedef enum
C_EXCHANGE,
C_BULLSEYE,
C_JUMPOVER,
+ C_FORTIFICATION,
+ C_FORTIFICATION_RED,
C_FUEL,
C_FUEL_RED,
C_ACTIONMODERED_NCTH,
diff --git a/Utils/XML_Items.cpp b/Utils/XML_Items.cpp
index 54df5473e..a7f0ffaa9 100644
--- a/Utils/XML_Items.cpp
+++ b/Utils/XML_Items.cpp
@@ -265,8 +265,8 @@ itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **at
strcmp(name, "Directional") == 0 ||
strcmp(name, "DrugType") == 0 ||
strcmp(name, "BlockIronSight") == 0 ||
- // Flugente: poison system
strcmp(name, "PoisonPercentage") == 0 ||
+ strcmp(name, "ItemFlag") == 0 ||
strcmp(name, "fFlags") == 0 ))
{
@@ -1333,12 +1333,16 @@ itemEndElementHandle(void *userData, const XML_Char *name)
pData->curElement = ELEMENT;
pData->curItem.blockironsight = (BOOLEAN) atol(pData->szCharData);
}
- // Flugente poison system
else if(strcmp(name, "PoisonPercentage") == 0)
{
pData->curElement = ELEMENT;
pData->curItem.bPoisonPercentage = (INT16) atol(pData->szCharData);
}
+ else if(strcmp(name, "ItemFlag") == 0)
+ {
+ pData->curElement = ELEMENT;
+ pData->curItem.usItemFlag = (UINT32) atol(pData->szCharData);
+ }
pData->maxReadDepth--;
@@ -1954,6 +1958,8 @@ BOOLEAN WriteItemStats()
FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].drugtype );
FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].blockironsight );
+
+ FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].usItemFlag );
// Flugente poison system
FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].bPoisonPercentage );