From 760a1b16f18f45d6a428d9509aaf1b2913bb49a8 Mon Sep 17 00:00:00 2001 From: Flugente Date: Sun, 7 Sep 2014 00:11:16 +0000 Subject: [PATCH] Feature improvement: - via StructureConstruct.xml and StructureDeconstruct.xml, one can now define which structures can be removed and created via items and the fortifications feature. For more information, see http://www.ja-galaxy-forum.com/ubbthreads.php/topics/335557#Post335557 does not break savegame compatibility. Requires GameDir >= r2140. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7491 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- Init.cpp | 8 + Tactical/Handle Items.cpp | 437 +++++++++++++++-------- Tactical/Handle Items.h | 34 +- Tactical/Handle UI.cpp | 17 +- Tactical/Item Types.h | 6 +- Tactical/Soldier Ani.cpp | 8 +- Tactical/Soldier Control.cpp | 300 ++++++++-------- Tactical/Soldier Control.h | 2 +- Tactical/Tactical_VS2005.vcproj | 8 + Tactical/Tactical_VS2008.vcproj | 8 + Tactical/Tactical_VS2010.vcxproj | 2 + Tactical/Tactical_VS2010.vcxproj.filters | 6 + Tactical/Tactical_VS2013.vcxproj | 2 + Tactical/Tactical_VS2013.vcxproj.filters | 6 + Tactical/UI Cursors.cpp | 35 +- Tactical/XML.h | 9 + Tactical/XML_StructureConstruct.cpp | 242 +++++++++++++ Tactical/XML_StructureDeconstruct.cpp | 235 ++++++++++++ 18 files changed, 1021 insertions(+), 344 deletions(-) create mode 100644 Tactical/XML_StructureConstruct.cpp create mode 100644 Tactical/XML_StructureDeconstruct.cpp diff --git a/Init.cpp b/Init.cpp index cd9df36b..ad0d5e14 100644 --- a/Init.cpp +++ b/Init.cpp @@ -373,6 +373,14 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) strcat( fileName, DISEASEFILENAME ); SGP_THROW_IFFALSE( ReadInDiseaseStats( fileName ), DISEASEFILENAME ); + strcpy(fileName, directoryName); + strcat(fileName, STRUCTUREDECONSTRUCTFILENAME); + SGP_THROW_IFFALSE(ReadInStructureDeconstructStats(fileName),STRUCTUREDECONSTRUCTFILENAME); + + strcpy(fileName, directoryName); + strcat(fileName, STRUCTURECONSTRUCTFILENAME); + SGP_THROW_IFFALSE(ReadInStructureConstructStats(fileName),STRUCTURECONSTRUCTFILENAME); + strcpy(fileName, directoryName); strcat(fileName, MERCHANTSFILENAME); SGP_THROW_IFFALSE(ReadInMerchantStats(fileName),MERCHANTSFILENAME); diff --git a/Tactical/Handle Items.cpp b/Tactical/Handle Items.cpp index 2bb7ebd2..fa98950a 100644 --- a/Tactical/Handle Items.cpp +++ b/Tactical/Handle Items.cpp @@ -86,6 +86,9 @@ UINT8 gubLastTripwire = 0; // set to TRUE if shift+click was pressed for planting bomb - will use for Improved Bomb Planting feature BOOLEAN gfShiftBombPlant = FALSE; +// Flugente: (de-)construct structures +STRUCTURE_DECONSTRUCT gStructureDeconstruct[STRUCTURE_DECONSTRUCT_MAX]; +STRUCTURE_CONSTRUCT gStructureConstruct[STRUCTURE_CONSTRUCT_MAX]; LEVELNODE *AddItemGraphicToWorld( INVTYPE *pItem, INT32 sGridNo, UINT8 ubLevel ); INT8 GetListMouseHotSpot( INT16 sLargestLineWidth, INT8 bNumItemsListed, INT16 sFontX, INT16 sFontY, INT8 bCurStart ); @@ -1148,14 +1151,21 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa } } - // Flugente: sandbag stuff - if ( HasItemFlag(usHandItem, (EMPTY_SANDBAG|FULL_SANDBAG|SHOVEL|CONCERTINA)) ) + // Flugente: (de-)construct structures + if ( HasItemFlag( usHandItem, EMPTY_SANDBAG ) || IsStructureDeconstructItem( usHandItem, sGridNo, pSoldier ) || IsStructureConstructItem( usHandItem, sGridNo, pSoldier ) ) { // 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)) ) + if ( HasItemFlag(usHandItem, EMPTY_SANDBAG) ) { sAPCost = GetAPsForMultiTurnAction( pSoldier, MTA_FILL_SANDBAG ); + // we can only do this on certain terraintypes + INT8 bOverTerrainType = GetTerrainType( sGridNo ); + if ( bOverTerrainType != FLAT_GROUND && bOverTerrainType != DIRT_ROAD && bOverTerrainType != LOW_GRASS ) + { + return(ITEM_HANDLE_REFUSAL); + } + // check if we have a shovel in our second hand OBJECTTYPE* pShovelObj = &(pSoldier->inv[SECONDHANDPOS]); @@ -1163,39 +1173,40 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa { return( ITEM_HANDLE_REFUSAL ); } - - // we can only do this on certain terraintypes - INT8 bOverTerrainType = GetTerrainType( sGridNo ); - if( bOverTerrainType != FLAT_GROUND && bOverTerrainType != DIRT_ROAD && bOverTerrainType != LOW_GRASS ) - { - return( ITEM_HANDLE_REFUSAL ); - } - } - // if we have a shovel in our hands, the targeted gridno must be a fortification (debris will do for this check) - else if ( HasItemFlag(usHandItem, (SHOVEL)) ) - { - sAPCost = GetAPsForMultiTurnAction( pSoldier, MTA_REMOVE_FORTIFY ); - - STRUCTURE* pStruct = FindStructure(sGridNo, STRUCTURE_GENERIC); - - if ( !pStruct ) - { - return( ITEM_HANDLE_REFUSAL ); - } - } + } else { - sAPCost = GetAPsForMultiTurnAction( pSoldier, MTA_FORTIFY ); + // if there is a structure, see if we can deconstruct it, if not, see if we can construct something + STRUCTURE* pStruct = FindStructure( sGridNo, (STRUCTURE_GENERIC | STRUCTURE_WIREFENCE) ); + + if ( pStruct ) + { + if ( !IsStructureDeconstructItem( usHandItem, sGridNo, pSoldier ) ) + return(ITEM_HANDLE_REFUSAL); + + sAPCost = GetAPsForMultiTurnAction( pSoldier, MTA_REMOVE_FORTIFY ); + } + else + { + if ( !IsStructureConstructItem( usHandItem, sGridNo, pSoldier ) ) + return(ITEM_HANDLE_REFUSAL); + + sAPCost = GetAPsForMultiTurnAction( pSoldier, MTA_FORTIFY ); + } } - sActionGridNo = FindAdjacentGridEx( pSoldier, sGridNo, &ubDirection, &sAdjustedGridNo, TRUE, FALSE ); + // we are at pSoldier->sGridNo and the action takes place at sGridNo + // we need to find out in which direction we need to look + // sActionGridNo is the gridno we are supposed to sit + ubDirection = GetDirectionToGridNoFromGridNo( sGridNo, pSoldier->sGridNo ); + + sActionGridNo = FindAdjacentGridEx( pSoldier, sGridNo, &ubDirection, &sAdjustedGridNo, FALSE, FALSE ); - if ( sActionGridNo != -1 ) + if ( !TileIsOutOfBounds( sActionGridNo ) ) { // Calculate AP costs... - sAPCost += PlotPath( pSoldier, sActionGridNo, NO_COPYROUTE, FALSE, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints); + sAPCost += PlotPath( pSoldier, sActionGridNo, NO_COPYROUTE, FALSE, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints ); - //if ( EnoughPoints( pSoldier, sAPCost, 0, fFromUI ) ) if ( pSoldier->bActionPoints > 0 ) { // CHECK IF WE ARE AT THIS GRIDNO NOW @@ -1203,7 +1214,7 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa { // SEND PENDING ACTION pSoldier->aiData.ubPendingAction = MERC_BUILD_FORTIFICATION; - pSoldier->aiData.sPendingActionData2 = sAdjustedGridNo; + pSoldier->aiData.sPendingActionData2 = sGridNo; pSoldier->aiData.bPendingActionData3 = ubDirection; pSoldier->aiData.ubPendingActionAnimCount = 0; @@ -1212,7 +1223,7 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa } else { - pSoldier->EVENT_SoldierBuildStructure( sAdjustedGridNo, ubDirection ); + pSoldier->EVENT_SoldierBuildStructure( sGridNo, ubDirection ); } // OK, set UI @@ -6693,7 +6704,37 @@ void SoldierStealItemFromSoldier( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, SetCustomizableTimerCallbackAndDelay( 1000, CheckForPickedOwnership, TRUE ); } -BOOLEAN BuildFortification( INT32 sGridNo, UINT32 flag ) +// can we construct a structure with this item? +BOOLEAN IsStructureConstructItem(UINT16 usItem, INT32 sGridNo, SOLDIERTYPE* pSoldier) +{ + if ( !usItem || TileIsOutOfBounds( sGridNo ) ) + return FALSE; + + for ( UINT16 i = 0; i < STRUCTURE_CONSTRUCT_MAX; ++i ) + { + if ( usItem == gStructureConstruct[i].usCreationItem ) + return TRUE; + } + + return FALSE; +} + +// can we remove a structure with this item? +BOOLEAN IsStructureDeconstructItem( UINT16 usItem, INT32 sGridNo, SOLDIERTYPE* pSoldier ) +{ + if ( !usItem || TileIsOutOfBounds( sGridNo ) ) + return FALSE; + + for ( UINT16 i = 0; i < STRUCTURE_DECONSTRUCT_MAX; ++i ) + { + if ( usItem == gStructureDeconstruct[i].usDeconstructItem ) + return TRUE; + } + + return FALSE; +} + +BOOLEAN BuildFortification( INT32 sGridNo, SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ) { UINT32 fHeadType; UINT16 usUseIndex; @@ -6702,146 +6743,202 @@ BOOLEAN BuildFortification( INT32 sGridNo, UINT32 flag ) BOOLEAN fOkayToAdd; UINT8 ubDirection; - if ( gusSelectedSoldier == NOBODY ) + // we need a valid soldier and a valid object + if ( !pSoldier || !pObj ) return FALSE; - if( gbWorldSectorZ > 0 || gsInterfaceLevel > 0) - { + // no building on roofs + if( gsInterfaceLevel > 0 ) + return FALSE; + + // needs to be a valid location + if ( TileIsOutOfBounds( sGridNo ) ) return FALSE; - } - if( InARoom( sGridNo, NULL ) ) - return FALSE; + //if( InARoom( sGridNo, NULL ) ) + //return FALSE; + // don't build in water INT8 bOverTerrainType = GetTerrainType( sGridNo ); if( bOverTerrainType == MED_WATER || bOverTerrainType == DEEP_WATER || bOverTerrainType == LOW_WATER ) return FALSE; - UINT16 CurrentStruct = NO_TILE; - - if ( sGridNo < 0x80000000 ) + ubDirection = pSoldier->ubDirection; + + // we'll check wether this item is in our index of known creation items + BOOLEAN indexfound = FALSE; + INT16 structureconstructindex = -1; + for (UINT16 i = 0; i < STRUCTURE_DECONSTRUCT_MAX; ++i) { - ubDirection = MercPtrs[ gusSelectedSoldier ]->ubDirection; + if ( indexfound ) + break; - if ( (flag & CONCERTINA) != 0 ) + if ( pObj->usItem == gStructureConstruct[i].usCreationItem ) { - // 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 ( !gStructureConstruct[i].northtilevector.empty( ) ) { - if ( (_strnicmp(gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiType ], "spot_1.sti", 10) == 0) ) - { - usUseObjIndex = uiType; - break; - } + usUseIndex = gStructureConstruct[i].northtilevector[Random( gStructureConstruct[i].northtilevector.size( ) )]; + structureconstructindex = i; + indexfound = TRUE; } - else if( (_strnicmp(gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiType ], "sandbag.sti", 11) == 0) ) + break; + case SOUTH: + if ( !gStructureConstruct[i].southtilevector.empty( ) ) + { + usUseIndex = gStructureConstruct[i].southtilevector[Random( gStructureConstruct[i].southtilevector.size( ) )]; + structureconstructindex = i; + indexfound = TRUE; + } + break; + case WEST: + if ( !gStructureConstruct[i].westtilevector.empty( ) ) + { + usUseIndex = gStructureConstruct[i].westtilevector[Random( gStructureConstruct[i].westtilevector.size( ) )]; + structureconstructindex = i; + indexfound = TRUE; + } + break; + case EAST: + if ( !gStructureConstruct[i].easttilevector.empty( ) ) + { + usUseIndex = gStructureConstruct[i].easttilevector[Random( gStructureConstruct[i].easttilevector.size( ) )]; + structureconstructindex = i; + indexfound = TRUE; + } + break; + + default: + // for all other directions, just pick one tile, it doesn not matter from which direction + if ( !gStructureConstruct[i].northtilevector.empty( ) ) + { + usUseIndex = gStructureConstruct[i].northtilevector[Random( gStructureConstruct[i].northtilevector.size( ) )]; + structureconstructindex = i; + indexfound = TRUE; + } + + if ( !indexfound && !gStructureConstruct[i].southtilevector.empty( ) ) + { + usUseIndex = gStructureConstruct[i].southtilevector[Random( gStructureConstruct[i].southtilevector.size( ) )]; + structureconstructindex = i; + indexfound = TRUE; + } + + if ( !indexfound && !gStructureConstruct[i].westtilevector.empty( ) ) + { + usUseIndex = gStructureConstruct[i].westtilevector[Random( gStructureConstruct[i].westtilevector.size( ) )]; + structureconstructindex = i; + indexfound = TRUE; + } + + if ( !indexfound && !gStructureConstruct[i].easttilevector.empty( ) ) + { + usUseIndex = gStructureConstruct[i].easttilevector[Random( gStructureConstruct[i].easttilevector.size( ) )]; + structureconstructindex = i; + indexfound = TRUE; + } + break; + } + } + } + + if ( structureconstructindex < 0 ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szMTATextStr[STR_MTA_CANNOT_BUILD] ); + return FALSE; + } + + // search wether structure exists in the current tilesets. If not, well, too bad + for (UINT32 uiType = 0; uiType < giNumberOfTileTypes; ++uiType) + { + if( gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiType ][0] ) + { + if ( structureconstructindex >= 0 ) + { + if ( !_strnicmp(gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiType ], gStructureConstruct[structureconstructindex].szTileSetName, 10) ) { usUseObjIndex = uiType; break; } } } + } - if ( !usUseObjIndex ) + if ( !usUseObjIndex ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szMTATextStr[ STR_MTA_CANNOT_BUILD ] ); + return FALSE; + } + + // consumables are removed on creation + if ( structureconstructindex >= 0 && gStructureConstruct[structureconstructindex].usItemStatusLoss ) + { + if ( (*pObj)[0]->data.objectStatus <= gStructureConstruct[structureconstructindex].usItemStatusLoss ) { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szMTATextStr[ STR_MTA_CANNOT_BUILD ] ); - return FALSE; + UINT16 usItem = pObj->usItem; + + // Erase 'material' item from our hand - we 'use' it to build the structure + DeleteObj( &(pSoldier->inv[HANDPOS]) ); + + // sevenfm: auto-taking of items + if ( !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) && gfShiftBombPlant ) + { + pSoldier->TakeNewItemFromInventory( pObj->usItem ); + } } - - // 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) ) + else { - // 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; + (*pObj)[0]->data.objectStatus -= gStructureConstruct[structureconstructindex].usItemStatusLoss; } } - else if ( CurrentStruct == ERASE_TILE && sGridNo < 0x80000000 ) + + // TODO: if we create an earth pile, create a decal (signifiying the 'hole' we created at our position) + + // 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) ) { - RemoveAllStructsOfTypeRange( sGridNo, FIRSTOSTRUCT, LASTOSTRUCT ); - RemoveAllShadowsOfTypeRange( sGridNo, FIRSTSHADOW, LASTSHADOW ); + // 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; } return FALSE; } -BOOLEAN RemoveFortification( INT32 sGridNo ) +BOOLEAN RemoveFortification( INT32 sGridNo, SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ) { - STRUCTURE* pStruct = FindStructure(sGridNo, STRUCTURE_GENERIC); + // we need a valid soldier and a valid object + if ( !pSoldier || !pObj ) + return FALSE; + + // not on roofs + if ( gsInterfaceLevel > 0 ) + return FALSE; + + // needs to be a valid location + if ( TileIsOutOfBounds( sGridNo ) ) + return FALSE; + + STRUCTURE* pStruct = FindStructure( sGridNo, (STRUCTURE_GENERIC | STRUCTURE_WIREFENCE) ); if ( pStruct != NULL ) { @@ -6850,34 +6947,58 @@ BOOLEAN RemoveFortification( INT32 sGridNo ) if ( pNode ) { + UINT16 usIndex = pNode->usIndex; UINT32 uiTileType = 0; - if ( GetTileType( pNode->usIndex, &uiTileType ) ) + if ( GetTileType( usIndex, &uiTileType ) ) { - UINT16 usIndex = pNode->usIndex; - - // Check if we are a sandbag - if ( _strnicmp( gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiTileType ], "sandbag.sti", 11) == 0 ) + for (UINT16 i = 0; i < STRUCTURE_DECONSTRUCT_MAX; ++i) { - // Remove old graphic - ApplyMapChangesToMapTempFile( TRUE ); - - RemoveStruct( sGridNo, pNode->usIndex ); - if ( !GridNoIndoors( sGridNo ) && gTileDatabase[ usIndex ].uiFlags & HAS_SHADOW_BUDDY && gTileDatabase[ usIndex ].sBuddyNum != -1 ) + // item we have in our hand must be one with which we can deconstruct this + if ( pObj->usItem == gStructureDeconstruct[i].usDeconstructItem ) { - RemoveShadow( sGridNo, gTileDatabase[ usIndex ].sBuddyNum ); + // Check if we are a sandbag or a earth pile + if ( !_strnicmp( gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiTileType ], gStructureDeconstruct[i].szTileSetName, 11) ) + { + // we have to check wether this specific structure can be removed. Just checking the tileset name won't be enough. + // For example, we could have a set consisting of crates and piles of earth, which we want to remove via applying a shovel on it. + // We only want to do this on the earth piles, of course - flattening crates via a shovel would be odd :-) + UINT8 numbertofind = (UINT8)(pStruct->pDBStructureRef->pDBStructure->usStructureNumber); + + UINT8 size = gStructureDeconstruct[i].tilevector.size(); + for ( UINT8 j = 0; j < size; ++j) + { + if ( gStructureDeconstruct[i].tilevector[j] == numbertofind ) + { + // 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 ); + } + + RecompileLocalMovementCosts(sGridNo); + + // Turn off permanent changes.... + ApplyMapChangesToMapTempFile( FALSE ); + SetRenderFlags( RENDER_FLAG_FULL ); + + // eventually create item + if ( gStructureDeconstruct[i].usItemToCreate && gStructureDeconstruct[i].usCreatedItemStatus ) + { + // when creating the object, make it have at least 1% status + CreateItem( gStructureDeconstruct[i].usItemToCreate, max(1, gStructureDeconstruct[i].usCreatedItemStatus), &gTempObject ); + + AddItemToPool( sGridNo, &gTempObject, 1, 0, 0, -1 ); + } + + return TRUE; + } + } + } } - - // 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; } } } diff --git a/Tactical/Handle Items.h b/Tactical/Handle Items.h index 90d60259..95bf1083 100644 --- a/Tactical/Handle Items.h +++ b/Tactical/Handle Items.h @@ -79,6 +79,33 @@ typedef struct } ITEM_POOL_LOCATOR; +// Flugente: we can construct and deconstruct map structures via items. +typedef struct { + UINT16 usDeconstructItem; // the item that has to be used to deconstruct the structure + UINT16 usItemToCreate; // the item that will be created when we deconstruct a structure + UINT8 usCreatedItemStatus; // status of the item to create + char szTileSetName[20]; // name of the tileset + std::vector tilevector; // structures in the tileset that we can deconstruct +} STRUCTURE_DECONSTRUCT; + +#define STRUCTURE_DECONSTRUCT_MAX 200 + +extern STRUCTURE_DECONSTRUCT gStructureDeconstruct[STRUCTURE_DECONSTRUCT_MAX]; + +typedef struct { + UINT16 usCreationItem; // the item that will be consumed when creating the structure + UINT8 usItemStatusLoss; // item will lose this number of status points + char szTileSetName[20]; // name of the tileset + std::vector northtilevector; // structures in the tileset we can create while facing north + std::vector southtilevector; // structures in the tileset we can create while facing south + std::vector easttilevector; // structures in the tileset we can create while facing east + std::vector westtilevector; // structures in the tileset we can create while facing west +} STRUCTURE_CONSTRUCT; + +#define STRUCTURE_CONSTRUCT_MAX 200 + +extern STRUCTURE_CONSTRUCT gStructureConstruct[STRUCTURE_CONSTRUCT_MAX]; + class SOLDIERTYPE; INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHandItem, BOOLEAN fFromUI ); void SoldierPickupItem( SOLDIERTYPE *pSoldier, INT32 iItemIndex, INT32 sGridNo, INT8 bZLevel ); @@ -180,8 +207,11 @@ UINT8 StealItems(SOLDIERTYPE* pSoldier,SOLDIERTYPE* pOpponent, UINT8* ubIndexRet BOOLEAN MarblesExistAtLocation( INT32 sGridNo, UINT8 ubLevel, INT32 * piItemIndex ); -BOOLEAN BuildFortification( INT32 sGridNo , UINT32 flag = FULL_SANDBAG ); // Flugente: build a structure, return true if sucessful -BOOLEAN RemoveFortification( INT32 sGridNo ); +// Flugente: build an deconstruct structures +BOOLEAN IsStructureConstructItem( UINT16 usItem, INT32 sGridNo, SOLDIERTYPE* pSoldier ); // can we construct a structure with this item? +BOOLEAN IsStructureDeconstructItem( UINT16 usItem, INT32 sGridNo, SOLDIERTYPE* pSoldier ); // can we remove a structure with this item? +BOOLEAN BuildFortification( INT32 sGridNo, SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ); // build a structure, return true if sucessful +BOOLEAN RemoveFortification( INT32 sGridNo, SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ); // remove a structure, return true if sucessful extern ITEM_POOL *gpItemPool;//dnl ch26 210909 diff --git a/Tactical/Handle UI.cpp b/Tactical/Handle UI.cpp index e9d1125e..b6d2abe4 100644 --- a/Tactical/Handle UI.cpp +++ b/Tactical/Handle UI.cpp @@ -4512,7 +4512,7 @@ BOOLEAN UIMouseOnValidAttackLocation( SOLDIERTYPE *pSoldier ) // 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)) ) + if ( pShovelObj && pShovelObj->exists() && HasItemFlag(pSoldier->inv[ SECONDHANDPOS ].usItem, (SHOVEL)) ) { INT8 bOverTerrainType = GetTerrainType( usMapPos ); if( bOverTerrainType == FLAT_GROUND || bOverTerrainType == DIRT_ROAD || bOverTerrainType == LOW_GRASS ) @@ -4521,19 +4521,20 @@ BOOLEAN UIMouseOnValidAttackLocation( SOLDIERTYPE *pSoldier ) } } } - else if ( HasItemFlag( (&(pSoldier->inv[HANDPOS]))->usItem, (SHOVEL)) ) + + if ( IsFortificationPossibleAtGridNo( usMapPos ) && IsStructureConstructItem( pSoldier->inv[HANDPOS].usItem, usMapPos, pSoldier ) ) { - STRUCTURE* pStruct = FindStructure(usMapPos, STRUCTURE_GENERIC); + return(TRUE); + } + else if ( IsStructureDeconstructItem( pSoldier->inv[HANDPOS].usItem, usMapPos, pSoldier ) ) + { + STRUCTURE* pStruct = FindStructure( usMapPos, (STRUCTURE_GENERIC | STRUCTURE_WIREFENCE) ); if ( pStruct ) { - return( TRUE ); + return(TRUE); } } - else if ( IsFortificationPossibleAtGridNo( usMapPos ) ) - { - return( TRUE ); - } } return( FALSE ); diff --git a/Tactical/Item Types.h b/Tactical/Item Types.h index 0d975e69..1a8e0734 100644 --- a/Tactical/Item Types.h +++ b/Tactical/Item Types.h @@ -731,9 +731,9 @@ extern OBJECTTYPE gTempObject; // 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 FULL_SANDBAG 0x00000002 //2 #define SHOVEL 0x00000004 //4 // a shovel is used for filling sandbags and other building-related tasks -#define CONCERTINA 0x00000008 //8 +//#define CONCERTINA 0x00000008 //8 #define WATER_DRUM 0x00000010 //16 // water drums allow to refill canteens in the sector they are in #define MEAT_BLOODCAT 0x00000020 //32 // retrieve this by gutting a bloodcat @@ -765,7 +765,7 @@ extern OBJECTTYPE gTempObject; #define SIGNAL_SHELL 0x04000000 //67108864 // this is a signal shell that precedes artillery barrages #define POWER_PACK 0x08000000 //134217728 // item continously powers an item it is attached to -#define SPOTTERITEM 0x10000000 //268435456 // binocular +//#define WOODENPLANK 0x10000000 //268435456 // wooden planks #define DISEASEPROTECTION_FACE 0x20000000 //536870912 // this item protects us from getting diseases by human contact if worn in a face slot #define DISEASEPROTECTION_HAND 0x40000000 //1073741824 // this item protects us from getting diseases by human contact if kept in inventory /*#define PLAYER_NET_4_LVL_4 0x80000000 //2147483648*/ diff --git a/Tactical/Soldier Ani.cpp b/Tactical/Soldier Ani.cpp index 092f548e..f2a5dcc9 100644 --- a/Tactical/Soldier Ani.cpp +++ b/Tactical/Soldier Ani.cpp @@ -3162,8 +3162,12 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) case 766: - // Say COOL quote - pSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 ); + // Flugente: if doing this action a lot, this gets annoying - only play sound sometimes + if ( Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) ) + { + // Say COOL quote + pSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 ); + } break; case 767: diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 415d8176..7fa3f1f3 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -16188,10 +16188,10 @@ UINT8 SOLDIERTYPE::GetMultiTurnAction( ) return usMultiTurnAction; } -void SOLDIERTYPE::StartMultiTurnAction( UINT8 usActionType ) +void SOLDIERTYPE::StartMultiTurnAction( UINT8 usActionType, INT32 asGridNo ) { // check wether we can perform any action at all - if ( !this->bActive || !this->bInSector || this->stats.bLife < OKLIFE || TileIsOutOfBounds( this->sGridNo ) || this->bCollapsed ) + if ( !this->bActive || !this->bInSector || this->stats.bLife < OKLIFE || TileIsOutOfBounds( asGridNo ) || this->bCollapsed ) return; // wether an action is possible or not depends on action itself (there are actions without a gridno) @@ -16200,7 +16200,7 @@ void SOLDIERTYPE::StartMultiTurnAction( UINT8 usActionType ) case MTA_FORTIFY: case MTA_REMOVE_FORTIFY: case MTA_FILL_SANDBAG: - if ( this->pathing.bLevel != 0 || gAnimControl[this->usAnimState].ubEndHeight == ANIM_PRONE || gAnimControl[this->usAnimState].ubEndHeight == ANIM_STAND ) + if ( this->pathing.bLevel != 0 ) return; break; } @@ -16213,8 +16213,8 @@ void SOLDIERTYPE::StartMultiTurnAction( UINT8 usActionType ) usMultiTurnAction = usActionType; // the action shall be performed on the gridno directly in front of us - sMTActionGridNo = NewGridNo( this->sGridNo, DirectionInc( this->ubDirection ) ); - + sMTActionGridNo = asGridNo; + // for now, adding and removing a structure has the same AP cost - that might change in the future bOverTurnAPS = GetAPsForMultiTurnAction( this, usMultiTurnAction ); @@ -16248,24 +16248,31 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( ) CancelMultiTurnAction( FALSE ); return FALSE; } - + // wether an action is possible or not depends on action itself (there are actions without a gridno) switch ( usMultiTurnAction ) { case MTA_FORTIFY: case MTA_REMOVE_FORTIFY: case MTA_FILL_SANDBAG: - if ( this->pathing.bLevel != 0 || gAnimControl[this->usAnimState].ubEndHeight == ANIM_PRONE || gAnimControl[this->usAnimState].ubEndHeight == ANIM_STAND ) + // building on a roof is forbidden! stopt his! + if ( this->pathing.bLevel != 0 ) { CancelMultiTurnAction( FALSE ); return FALSE; } + + // we have to be crouched, get out of here, set us to be crouched first + if ( gAnimControl[this->usAnimState].ubEndHeight != ANIM_CROUCH ) + { + return TRUE; + } break; default: // default: exit - { - CancelMultiTurnAction( FALSE ); - return FALSE; - } + { + CancelMultiTurnAction( FALSE ); + return FALSE; + } break; } @@ -16289,56 +16296,54 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( ) CancelMultiTurnAction( FALSE ); return FALSE; } - - // a static variable that is the item number of sandbags. Hardcoding item numbers is bad, that's why we will search for it. - static UINT16 fullsandbagnr = 1541; - + INT16 entireapcost = 0; INT16 entirebpcost = 0; switch ( usMultiTurnAction ) { - case MTA_FORTIFY: - { - entireapcost = GetAPsForMultiTurnAction( this, MTA_FORTIFY ); - entirebpcost = APBPConstants[BP_FORTIFICATION]; + case MTA_FORTIFY: + { + entireapcost = GetAPsForMultiTurnAction( this, MTA_FORTIFY ); + entirebpcost = APBPConstants[BP_FORTIFICATION]; - if ( !IsFortificationPossibleAtGridNo( this->sMTActionGridNo ) ) - fActionStillValid = FALSE; - else if ( !HasItemFlag( this->inv[HANDPOS].usItem, (FULL_SANDBAG | CONCERTINA) ) ) - fActionStillValid = FALSE; - } - break; - case MTA_REMOVE_FORTIFY: - { - entireapcost = GetAPsForMultiTurnAction( this, MTA_REMOVE_FORTIFY ); - entirebpcost = APBPConstants[BP_REMOVE_FORTIFICATION]; - - if ( !HasItemFlag( this->inv[HANDPOS].usItem, (SHOVEL) ) ) - fActionStillValid = FALSE; - } + if ( !IsFortificationPossibleAtGridNo( this->sMTActionGridNo ) ) + fActionStillValid = FALSE; + else if ( !IsStructureConstructItem( this->inv[HANDPOS].usItem, this->sMTActionGridNo, this ) ) + fActionStillValid = FALSE; + } break; - case MTA_FILL_SANDBAG: - { - entireapcost = GetAPsForMultiTurnAction( this, MTA_FILL_SANDBAG ); - entirebpcost = APBPConstants[BP_FILL_SANDBAG]; + case MTA_REMOVE_FORTIFY: + { + entireapcost = GetAPsForMultiTurnAction( this, MTA_REMOVE_FORTIFY ); + entirebpcost = APBPConstants[BP_REMOVE_FORTIFICATION]; - if ( !HasItemFlag( this->inv[HANDPOS].usItem, EMPTY_SANDBAG ) ) - fActionStillValid = FALSE; - else - { - INT8 bOverTerrainType = GetTerrainType( sGridNo ); - if ( bOverTerrainType != FLAT_GROUND && bOverTerrainType != DIRT_ROAD && bOverTerrainType != LOW_GRASS ) - fActionStillValid = FALSE; - else - { - // 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 ) ) - fActionStillValid = FALSE; - } - } - } + if ( !IsStructureDeconstructItem( this->inv[HANDPOS].usItem, this->sMTActionGridNo, this ) ) + fActionStillValid = FALSE; + } + break; + + case MTA_FILL_SANDBAG: + { + entireapcost = GetAPsForMultiTurnAction( this, MTA_FILL_SANDBAG ); + entirebpcost = APBPConstants[BP_FILL_SANDBAG]; + + if ( !HasItemFlag( this->inv[HANDPOS].usItem, EMPTY_SANDBAG ) ) + fActionStillValid = FALSE; + else + { + INT8 bOverTerrainType = GetTerrainType( sGridNo ); + if ( bOverTerrainType != FLAT_GROUND && bOverTerrainType != DIRT_ROAD && bOverTerrainType != LOW_GRASS ) + fActionStillValid = FALSE; + else + { + // 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 ) ) + fActionStillValid = FALSE; + } + } + } break; } @@ -16351,25 +16356,25 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( ) // refresh animations switch ( usMultiTurnAction ) { - case MTA_FORTIFY: - case MTA_REMOVE_FORTIFY: - case MTA_FILL_SANDBAG: - { - // if we are not in turnbased and no enemies are around, we reduce the number of necessary action points to 0. No need to keep waiting if there's nobody around anyway - if ( !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) ) - bOverTurnAPS = 0; - // otherwise this might take longer, so we refresh our animation - else - { - if ( !is_networked ) - this->EVENT_InitNewSoldierAnim( CUTTING_FENCE, 0, FALSE ); - else - this->ChangeSoldierState( CUTTING_FENCE, 0, 0 ); + case MTA_FORTIFY: + case MTA_REMOVE_FORTIFY: + case MTA_FILL_SANDBAG: + { + // if we are not in turnbased and no enemies are around, we reduce the number of necessary action points to 0. No need to keep waiting if there's nobody around anyway + if ( !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) ) + bOverTurnAPS = 0; + // otherwise this might take longer, so we refresh our animation + else + { + if ( !is_networked ) + this->EVENT_InitNewSoldierAnim( CUTTING_FENCE, 0, FALSE ); + else + this->ChangeSoldierState( CUTTING_FENCE, 0, 0 ); - // as setting the new animation costs APBPConstants[AP_USEWIRECUTTERS] APs every time, account for that - this->bActionPoints += APBPConstants[AP_USEWIRECUTTERS]; - } - } + // as setting the new animation costs APBPConstants[AP_USEWIRECUTTERS] APs every time, account for that + this->bActionPoints += APBPConstants[AP_USEWIRECUTTERS]; + } + } break; } @@ -16378,73 +16383,59 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( ) { switch ( usMultiTurnAction ) { - case MTA_FORTIFY: - { - // Build the thing - if ( BuildFortification( this->sMTActionGridNo, Item[pObj->usItem].usItemFlag ) ) - { - UINT16 usItem = pObj->usItem; - // Erase 'material' item from our hand - we 'use' it to build the structure - DeleteObj( &(this->inv[HANDPOS]) ); - // sevenfm: auto-taking of items - if ( !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) && gfShiftBombPlant ) - { - TakeNewItemFromInventory( usItem ); - } + case MTA_FORTIFY: + { + // Build the thing + if ( BuildFortification( this->sMTActionGridNo, this, pObj ) ) + { + // we gain a bit of experience... + StatChange( this, STRAMT, 4, TRUE ); + StatChange( this, HEALTHAMT, 2, TRUE ); + } + } + break; - // we gain a bit of experience... - StatChange( this, STRAMT, 4, TRUE ); - StatChange( this, HEALTHAMT, 2, TRUE ); - } - } - break; + case MTA_REMOVE_FORTIFY: + { + if ( RemoveFortification( this->sMTActionGridNo, this, pObj ) ) + { + // we gain a bit of experience... + StatChange( this, STRAMT, 3, TRUE ); + StatChange( this, HEALTHAMT, 2, TRUE ); + } + } + break; - case MTA_REMOVE_FORTIFY: - { - if ( RemoveFortification( this->sMTActionGridNo ) ) - { - // eventually search for the number of a sandbag item - if ( HasItemFlag( fullsandbagnr, FULL_SANDBAG ) || GetFirstItemWithFlag( &fullsandbagnr, FULL_SANDBAG ) ) - { - CreateItem( fullsandbagnr, 100, &gTempObject ); + case MTA_FILL_SANDBAG: + { + // eventually search for the number of a sandbag item + UINT16 fullsandbagnr = Item[this->inv[HANDPOS].usItem].usBuddyItem; + if ( fullsandbagnr ) + { + INT8 bObjSlot = HANDPOS; + UINT16 usItem = pObj->usItem; - AddItemToPool( this->sMTActionGridNo, &gTempObject, 1, 0, 0, -1 ); + CreateItem( fullsandbagnr, 100, &gTempObject ); + if ( !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) && gfShiftBombPlant ) + { + // sevenfm: drop filled sandbag to the ground and take new empty from inventory + AddItemToPool( this->sGridNo, &gTempObject, 1, 0, 0, -1 ); + DeleteObj( &(this->inv[HANDPOS]) ); + TakeNewItemFromInventory( usItem ); + } + else + { + SwapObjs( this, bObjSlot, &gTempObject, TRUE ); + } - // we gain a bit of experience... - StatChange( this, STRAMT, 3, TRUE ); - StatChange( this, HEALTHAMT, 2, TRUE ); - } - } - } - break; + // sevenfm: added this to correctly update interface + DirtyMercPanelInterface( this, DIRTYLEVEL2 ); - case MTA_FILL_SANDBAG: - { - // eventually search for the number of a sandbag item - if ( HasItemFlag( fullsandbagnr, FULL_SANDBAG ) || GetFirstItemWithFlag( &fullsandbagnr, FULL_SANDBAG ) ) - { - INT8 bObjSlot = HANDPOS; - UINT16 usItem = pObj->usItem; - - CreateItem( fullsandbagnr, 100, &gTempObject ); - if ( !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) && gfShiftBombPlant ) - { // sevenfm: drop filled sandbag to the ground and take new empty from inventory - AddItemToPool( this->sGridNo, &gTempObject, 1, 0, 0, -1 ); - DeleteObj( &(this->inv[HANDPOS]) ); - TakeNewItemFromInventory( usItem ); - } - else - { - SwapObjs( this, bObjSlot, &gTempObject, TRUE ); - } - // sevenfm: added this to correctly update interface - DirtyMercPanelInterface( this, DIRTYLEVEL2 ); - - // we gain a bit of experience... - StatChange( this, STRAMT, 1, TRUE ); - StatChange( this, HEALTHAMT, 1, TRUE ); - } - } + // we gain a bit of experience... + StatChange( this, STRAMT, 1, TRUE ); + StatChange( this, HEALTHAMT, 1, TRUE ); + } + } break; } @@ -19742,19 +19733,16 @@ void SOLDIERTYPE::EVENT_SoldierBuildStructure( INT32 sGridNo, UINT8 ubDirection } } + // CHANGE DIRECTION AND GOTO ANIMATION NOW + this->EVENT_SetSoldierDesiredDirection( ubDirection ); + this->EVENT_SetSoldierDirection( ubDirection ); + // do checks here... OBJECTTYPE* pObj = &(this->inv[HANDPOS]); - if ( pObj && pObj->exists( ) && HasItemFlag( this->inv[HANDPOS].usItem, (EMPTY_SANDBAG | FULL_SANDBAG | SHOVEL | CONCERTINA) ) ) + if ( pObj && pObj->exists( ) && (HasItemFlag( this->inv[HANDPOS].usItem, EMPTY_SANDBAG ) || IsStructureConstructItem( this->inv[HANDPOS].usItem, sGridNo, this ) || IsStructureDeconstructItem( this->inv[HANDPOS].usItem, sGridNo, this ) ) ) { - if ( HasItemFlag( this->inv[HANDPOS].usItem, (FULL_SANDBAG | CONCERTINA) ) ) - { - // Build the thing - this->StartMultiTurnAction( MTA_FORTIFY ); - - fSuccess = TRUE; - } - else if ( HasItemFlag( this->inv[HANDPOS].usItem, (EMPTY_SANDBAG) ) ) + if ( HasItemFlag( this->inv[HANDPOS].usItem, EMPTY_SANDBAG ) ) { INT8 bOverTerrainType = GetTerrainType( sGridNo ); if ( bOverTerrainType == FLAT_GROUND || bOverTerrainType == DIRT_ROAD || bOverTerrainType == LOW_GRASS ) @@ -19762,19 +19750,33 @@ void SOLDIERTYPE::EVENT_SoldierBuildStructure( INT32 sGridNo, UINT8 ubDirection // 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) ) ) + if ( pShovelObj && pShovelObj->exists( ) && HasItemFlag( this->inv[SECONDHANDPOS].usItem, SHOVEL ) ) { - this->StartMultiTurnAction( MTA_FILL_SANDBAG ); + this->StartMultiTurnAction( MTA_FILL_SANDBAG, sGridNo ); fSuccess = TRUE; } } } - else if ( HasItemFlag( this->inv[HANDPOS].usItem, (SHOVEL) ) ) + else { - this->StartMultiTurnAction( MTA_REMOVE_FORTIFY ); + // it is possible that an item is used in both constructing and deconstructing. We thus check wether a structure already exists at sGridNo to dedcut the players intention + // if there is a structure, we will remove this fortification. If there isn't, then we will dig and create a earth pile + STRUCTURE* pStruct = FindStructure( sGridNo, STRUCTURE_GENERIC ); - fSuccess = TRUE; + if ( !pStruct && IsStructureConstructItem( this->inv[HANDPOS].usItem, sGridNo, this ) ) + { + // Build the thing + this->StartMultiTurnAction( MTA_FORTIFY, sGridNo ); + + fSuccess = TRUE; + } + else if ( IsStructureDeconstructItem( this->inv[HANDPOS].usItem, sGridNo, this ) ) + { + this->StartMultiTurnAction( MTA_REMOVE_FORTIFY, sGridNo ); + + fSuccess = TRUE; + } } } @@ -19785,10 +19787,6 @@ void SOLDIERTYPE::EVENT_SoldierBuildStructure( INT32 sGridNo, UINT8 ubDirection } else { - // 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 diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index 885a7e11..dca27de5 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -1775,7 +1775,7 @@ public: // Flugente: multi-turn actions UINT8 GetMultiTurnAction(); - void StartMultiTurnAction(UINT8 usActionType); + void StartMultiTurnAction( UINT8 usActionType, INT32 asGridNo ); void CancelMultiTurnAction(BOOLEAN fFinished); BOOLEAN UpdateMultiTurnAction(); diff --git a/Tactical/Tactical_VS2005.vcproj b/Tactical/Tactical_VS2005.vcproj index ee2518aa..860370bc 100644 --- a/Tactical/Tactical_VS2005.vcproj +++ b/Tactical/Tactical_VS2005.vcproj @@ -1240,6 +1240,14 @@ RelativePath=".\XML_SpreadPatterns.cpp" > + + + + diff --git a/Tactical/Tactical_VS2008.vcproj b/Tactical/Tactical_VS2008.vcproj index 83c4e6bf..0b7299a9 100644 --- a/Tactical/Tactical_VS2008.vcproj +++ b/Tactical/Tactical_VS2008.vcproj @@ -1242,6 +1242,14 @@ RelativePath=".\XML_SpreadPatterns.cpp" > + + + + diff --git a/Tactical/Tactical_VS2010.vcxproj b/Tactical/Tactical_VS2010.vcxproj index d08150e9..90f75dfe 100644 --- a/Tactical/Tactical_VS2010.vcxproj +++ b/Tactical/Tactical_VS2010.vcxproj @@ -247,6 +247,8 @@ + + diff --git a/Tactical/Tactical_VS2010.vcxproj.filters b/Tactical/Tactical_VS2010.vcxproj.filters index c27813a7..b3502754 100644 --- a/Tactical/Tactical_VS2010.vcxproj.filters +++ b/Tactical/Tactical_VS2010.vcxproj.filters @@ -689,5 +689,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Tactical/Tactical_VS2013.vcxproj b/Tactical/Tactical_VS2013.vcxproj index 81d9a728..b5e0ed1c 100644 --- a/Tactical/Tactical_VS2013.vcxproj +++ b/Tactical/Tactical_VS2013.vcxproj @@ -248,6 +248,8 @@ + + diff --git a/Tactical/Tactical_VS2013.vcxproj.filters b/Tactical/Tactical_VS2013.vcxproj.filters index 2c3f49e8..a44fe27b 100644 --- a/Tactical/Tactical_VS2013.vcxproj.filters +++ b/Tactical/Tactical_VS2013.vcxproj.filters @@ -601,6 +601,12 @@ Source Files + + + Source Files + + + Source Files Source Files diff --git a/Tactical/UI Cursors.cpp b/Tactical/UI Cursors.cpp index 40fd2eac..4590c594 100644 --- a/Tactical/UI Cursors.cpp +++ b/Tactical/UI Cursors.cpp @@ -2209,12 +2209,12 @@ UINT8 HandleFortificationCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 ui 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)) ) + 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)) ) + if ( pShovelObj && (pShovelObj->exists()) && HasItemFlag(pSoldier->inv[ SECONDHANDPOS ].usItem, SHOVEL) ) { INT8 bOverTerrainType = GetTerrainType( sGridNo ); if( bOverTerrainType == FLAT_GROUND || bOverTerrainType == DIRT_ROAD || bOverTerrainType == LOW_GRASS ) @@ -2225,23 +2225,19 @@ UINT8 HandleFortificationCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 ui return( FORTIFICATION_RED_UICURSOR ); } - - if ( HasItemFlag( (&(pSoldier->inv[HANDPOS]))->usItem, (SHOVEL)) ) + + if ( IsFortificationPossibleAtGridNo( sGridNo ) && IsStructureConstructItem( pSoldier->inv[HANDPOS].usItem, sGridNo, pSoldier ) ) { - STRUCTURE* pStruct = FindStructure(sGridNo, STRUCTURE_GENERIC); + return( FORTIFICATION_GREY_UICURSOR ); + } + else if ( IsStructureDeconstructItem( pSoldier->inv[HANDPOS].usItem, sGridNo, pSoldier ) ) + { + STRUCTURE* pStruct = FindStructure( sGridNo, (STRUCTURE_GENERIC | STRUCTURE_WIREFENCE)); if ( pStruct ) { - return( FORTIFICATION_GREY_UICURSOR ); + return(FORTIFICATION_GREY_UICURSOR); } - else - return( FORTIFICATION_RED_UICURSOR ); - } - - // can we build something here? - if ( IsFortificationPossibleAtGridNo( sGridNo ) ) - { - return( FORTIFICATION_GREY_UICURSOR ); } return( FORTIFICATION_RED_UICURSOR ); @@ -2741,7 +2737,7 @@ void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos ) UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier ) { - UINT8 ubCursor; + UINT8 ubCursor; UINT16 usInHand; // If we are an EPC, do nothing.... @@ -2772,7 +2768,6 @@ UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier ) } } - if ( pSoldier->bWeaponMode == WM_ATTACHED_GL ) { // Flugente: if using a rifle grenade, only allow firing if there is a bullet in the gun's magazine (required for firing) @@ -2787,6 +2782,7 @@ UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier ) return( TRAJECTORYCURS ); } + if ( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST || ( pSoldier->bWeaponMode == WM_BURST && Item[pSoldier->inv[HANDPOS].usItem].grenadelauncher ) ) { if ( gGameSettings.fOptions [ TOPTION_GL_BURST_CURSOR ] ) @@ -2824,8 +2820,9 @@ UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier ) } } - // Flugente: cursor for building fortifications - if ( HasItemFlag(usInHand, (EMPTY_SANDBAG|FULL_SANDBAG|SHOVEL|CONCERTINA)) ) + // Flugente: cursor for constructing/deconstructing + // at the moment the gridno is not required in these functions, thus 1 suffices + if ( HasItemFlag( usInHand, EMPTY_SANDBAG ) || IsStructureConstructItem( usInHand, 1, pSoldier ) || IsStructureDeconstructItem( usInHand, 1, pSoldier ) ) ubCursor = FORTICURS; // Flugente: cursor for handcuffs @@ -2836,7 +2833,7 @@ UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier ) if ( ItemCanBeAppliedToOthers( usInHand ) ) { // if item is a bomb, only allow apply if hovering over a soldier (otherwise we cannot mine anymore) - if ( Item[ usInHand ].usItemClass == IC_BOMB ) + if ( Item[ usInHand ].usItemClass & IC_BOMB ) { INT32 usMapPos = NOWHERE; if ( GetMouseMapPos( &usMapPos ) ) diff --git a/Tactical/XML.h b/Tactical/XML.h index 1ff762d2..70fa274f 100644 --- a/Tactical/XML.h +++ b/Tactical/XML.h @@ -66,6 +66,8 @@ typedef PARSE_STAGE; #define DRUGSFILENAME "Items\\Drugs.xml" #define FOODFILENAME "Items\\Food.xml" #define FOODOPINIONFILENAME "Items\\FoodOpinion.xml" +#define STRUCTUREDECONSTRUCTFILENAME "Items\\StructureDeconstruct.xml" +#define STRUCTURECONSTRUCTFILENAME "Items\\StructureConstruct.xml" #define CLOTHESFILENAME "Items\\Clothes.xml" #define RANDOMITEMFILENAME "Items\\RandomItem.xml" #define AMMOFILENAME "Items\\AmmoStrings.xml" @@ -322,6 +324,13 @@ extern BOOLEAN WriteFoodOpinionStats(); extern BOOLEAN ReadInDiseaseStats( STR fileName ); extern BOOLEAN WriteDiseaseStats( ); +// Flugente: structure (de-)construct +extern BOOLEAN ReadInStructureDeconstructStats(STR fileName); +extern BOOLEAN WriteStructureDeconstructStats(); + +extern BOOLEAN ReadInStructureConstructStats(STR fileName); +extern BOOLEAN WriteStructureConstructStats(); + // Flugente: merchants extern BOOLEAN ReadInMerchantStats(STR fileName); extern BOOLEAN WriteMerchantStats(); diff --git a/Tactical/XML_StructureConstruct.cpp b/Tactical/XML_StructureConstruct.cpp new file mode 100644 index 00000000..0c8f7e5c --- /dev/null +++ b/Tactical/XML_StructureConstruct.cpp @@ -0,0 +1,242 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "overhead.h" + #include "Handle Items.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + STRUCTURE_CONSTRUCT curFood; + STRUCTURE_CONSTRUCT * curArray; + UINT32 maxArraySize; + + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef structureconstructParseData; + +UINT16 structureconstructcnt = 0; + +static void XMLCALL +structureconstructStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + structureconstructParseData * pData = (structureconstructParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "STRUCTURESLIST") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + memset(pData->curArray,0,sizeof(STRUCTURE_CONSTRUCT)*pData->maxArraySize); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "STRUCTURE") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + memset(&pData->curFood,0,sizeof(STRUCTURE_CONSTRUCT)); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "usCreationItem") == 0 || + strcmp(name, "usItemStatusLoss") == 0 || + strcmp(name, "szTileSetName") == 0 || + strcmp(name, "northfacingtile") == 0 || + strcmp(name, "southfacingtile" ) == 0 || + strcmp(name, "eastfacingtile" ) == 0 || + strcmp(name, "westfacingtile") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +structureconstructCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + structureconstructParseData * pData = (structureconstructParseData *)userData; + + if( (pData->currentDepth <= pData->maxReadDepth) && + (strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH) + ){ + strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData))); + } +} + + +static void XMLCALL +structureconstructEndElementHandle(void *userData, const XML_Char *name) +{ + structureconstructParseData * pData = (structureconstructParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "STRUCTURESLIST") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "STRUCTURE") == 0) + { + pData->curElement = ELEMENT_LIST; + + // we do NOT want to read the first entry -> move stuff by 1 + if(structureconstructcnt < pData->maxArraySize) + { + pData->curArray[structureconstructcnt] = pData->curFood; //write the data into the table + } + + ++structureconstructcnt; + } + else if(strcmp(name, "usCreationItem") == 0) + { + pData->curElement = ELEMENT; + pData->curFood.usCreationItem = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "usItemStatusLoss") == 0) + { + pData->curElement = ELEMENT; + pData->curFood.usItemStatusLoss = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "szTileSetName") == 0) + { + pData->curElement = ELEMENT; + + strncpy(pData->curFood.szTileSetName, pData->szCharData, 20); + } + else if(strcmp(name, "northfacingtile") == 0) + { + pData->curElement = ELEMENT; + pData->curFood.northtilevector.push_back( (UINT8) atol(pData->szCharData) ); + } + else if(strcmp(name, "southfacingtile") == 0) + { + pData->curElement = ELEMENT; + pData->curFood.southtilevector.push_back( (UINT8) atol(pData->szCharData) ); + } + else if ( strcmp( name, "eastfacingtile" ) == 0 ) + { + pData->curElement = ELEMENT; + pData->curFood.easttilevector.push_back( (UINT8)atol( pData->szCharData ) ); + } + else if ( strcmp( name, "westfacingtile" ) == 0 ) + { + pData->curElement = ELEMENT; + pData->curFood.westtilevector.push_back( (UINT8)atol( pData->szCharData ) ); + } + + pData->maxReadDepth--; + } + + pData->currentDepth--; +} + + + + +BOOLEAN ReadInStructureConstructStats(STR fileName) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + structureconstructParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading StructureConstruct.xml" ); + + // Open foods file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( FALSE ); + + uiFSize = FileGetSize(hFile); + lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1); + + //Read in block + if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) ) + { + MemFree(lpcBuffer); + return( FALSE ); + } + + lpcBuffer[uiFSize] = 0; //add a null terminator + + FileClose( hFile ); + + XML_SetElementHandler(parser, structureconstructStartElementHandle, structureconstructEndElementHandle); + XML_SetCharacterDataHandler(parser, structureconstructCharacterDataHandle); + + memset(&pData,0,sizeof(pData)); + pData.curArray = gStructureConstruct; + pData.maxArraySize = STRUCTURE_CONSTRUCT_MAX; + + XML_SetUserData(parser, &pData); + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in StructureConstruct.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + XML_ParserFree(parser); + + return( TRUE ); +} + +BOOLEAN WriteStructureConstructStats() +{ + //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"writefoodsstats"); + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( "TABLEDATA\\StructureConstruct out.xml", FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0; cnt < STRUCTURE_CONSTRUCT_MAX; ++cnt) + { + FilePrintf(hFile,"\t\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", gStructureConstruct[cnt].usCreationItem ); + FilePrintf(hFile,"\t\t%d\r\n", gStructureConstruct[cnt].usItemStatusLoss ); + FilePrintf(hFile,"\t\t%s\r\n", gStructureConstruct[cnt].szTileSetName ); + + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} diff --git a/Tactical/XML_StructureDeconstruct.cpp b/Tactical/XML_StructureDeconstruct.cpp new file mode 100644 index 00000000..a44e1f78 --- /dev/null +++ b/Tactical/XML_StructureDeconstruct.cpp @@ -0,0 +1,235 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "overhead.h" + #include "Handle Items.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + STRUCTURE_DECONSTRUCT curFood; + STRUCTURE_DECONSTRUCT * curArray; + UINT32 maxArraySize; + + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef structuredeconstructParseData; + +UINT16 structuredeconstructcnt = 0; + +static void XMLCALL +structuredeconstructStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + structuredeconstructParseData * pData = (structuredeconstructParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "STRUCTURESLIST") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + memset(pData->curArray,0,sizeof(STRUCTURE_DECONSTRUCT)*pData->maxArraySize); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "STRUCTURE") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + memset(&pData->curFood,0,sizeof(STRUCTURE_DECONSTRUCT)); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "usDeconstructItem") == 0 || + strcmp( name, "usItemToCreate" ) == 0 || + strcmp( name, "usCreatedItemStatus" ) == 0 || + strcmp(name, "szTileSetName") == 0 || + strcmp(name, "allowedtile") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +structuredeconstructCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + structuredeconstructParseData * pData = (structuredeconstructParseData *)userData; + + if( (pData->currentDepth <= pData->maxReadDepth) && + (strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH) + ){ + strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData))); + } +} + + +static void XMLCALL +structuredeconstructEndElementHandle(void *userData, const XML_Char *name) +{ + structuredeconstructParseData * pData = (structuredeconstructParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "STRUCTURESLIST") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "STRUCTURE") == 0) + { + pData->curElement = ELEMENT_LIST; + + if(structuredeconstructcnt < pData->maxArraySize) + { + pData->curArray[structuredeconstructcnt] = pData->curFood; //write the data into the table + } + + ++structuredeconstructcnt; + } + else if ( strcmp( name, "usDeconstructItem" ) == 0 ) + { + pData->curElement = ELEMENT; + pData->curFood.usDeconstructItem = (UINT16)atol( pData->szCharData ); + } + else if(strcmp(name, "usItemToCreate") == 0) + { + pData->curElement = ELEMENT; + pData->curFood.usItemToCreate = (UINT16) atol(pData->szCharData); + } + else if ( strcmp( name, "usCreatedItemStatus" ) == 0 ) + { + pData->curElement = ELEMENT; + pData->curFood.usCreatedItemStatus = (UINT8)atol( pData->szCharData ); + } + else if(strcmp(name, "szTileSetName") == 0) + { + pData->curElement = ELEMENT; + + strncpy(pData->curFood.szTileSetName, pData->szCharData, 20); + } + else if(strcmp(name, "allowedtile") == 0) + { + pData->curElement = ELEMENT; + pData->curFood.tilevector.push_back( (UINT8) atol(pData->szCharData) ); + } + + pData->maxReadDepth--; + } + + pData->currentDepth--; +} + + + + +BOOLEAN ReadInStructureDeconstructStats(STR fileName) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + structuredeconstructParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading StructureDeconstruct.xml" ); + + // Open foods file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( FALSE ); + + uiFSize = FileGetSize(hFile); + lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1); + + //Read in block + if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) ) + { + MemFree(lpcBuffer); + return( FALSE ); + } + + lpcBuffer[uiFSize] = 0; //add a null terminator + + FileClose( hFile ); + + + XML_SetElementHandler(parser, structuredeconstructStartElementHandle, structuredeconstructEndElementHandle); + XML_SetCharacterDataHandler(parser, structuredeconstructCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + pData.curArray = gStructureDeconstruct; + pData.maxArraySize = STRUCTURE_DECONSTRUCT_MAX; + + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in StructureDeconstruct.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + +BOOLEAN WriteStructureDeconstructStats() +{ + //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"writefoodsstats"); + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( "TABLEDATA\\StructureDeconstruct out.xml", FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0; cnt < STRUCTURE_DECONSTRUCT_MAX; ++cnt) + { + FilePrintf(hFile,"\t\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", gStructureDeconstruct[cnt].usDeconstructItem ); + FilePrintf(hFile,"\t\t%d\r\n", gStructureDeconstruct[cnt].usItemToCreate ); + FilePrintf(hFile,"\t\t%d\r\n", gStructureDeconstruct[cnt].usCreatedItemStatus ); + FilePrintf(hFile,"\t\t%s\r\n", gStructureDeconstruct[cnt].szTileSetName ); + + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +}