mirror of
https://github.com/1dot13/source.git
synced 2026-08-12 14:10:23 +02:00
New feature: interactive actions allow various actions (hacking/reading/drinking/...) from user-defined xml acttions. The exact results can be set in a lua function.
For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&th=23144&goto=346447&#msg_346447 This is fully savegame compatible. GameDir >= r2333 is required. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8278 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
+6
-1
@@ -2212,7 +2212,12 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
|
||||
}
|
||||
|
||||
// Flugente: add an icon if we are performing a multi-turn action
|
||||
if ( MercPtrs[ pFace->ubSoldierID ]->GetMultiTurnAction() > MTA_NONE )
|
||||
if ( MercPtrs[pFace->ubSoldierID]->GetMultiTurnAction( ) == MTA_HACK )
|
||||
{
|
||||
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons, 30 );
|
||||
bNumRightIcons++;
|
||||
}
|
||||
else if ( MercPtrs[ pFace->ubSoldierID ]->GetMultiTurnAction() > MTA_NONE )
|
||||
{
|
||||
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons, 14 );
|
||||
bNumRightIcons++;
|
||||
|
||||
@@ -1118,4 +1118,39 @@ BOOLEAN HasFoodInInventory( SOLDIERTYPE *pSoldier, BOOLEAN fCheckFood, BOOLEAN f
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void DrinkFromWaterTap( SOLDIERTYPE* pSoldier )
|
||||
{
|
||||
if ( !pSoldier )
|
||||
return;
|
||||
|
||||
// dont feed our machines
|
||||
if ( pSoldier->ubProfile == ROBOT || IsVehicle( pSoldier ) )
|
||||
return;
|
||||
|
||||
if ( gGameOptions.fFoodSystem )
|
||||
{
|
||||
INT32 watertoadd = max( 0, FoodMoraleMods[FOOD_NORMAL].bThreshold - pSoldier->bDrinkLevel );
|
||||
|
||||
if ( watertoadd > 0 )
|
||||
{
|
||||
AddFoodpoints( pSoldier->bDrinkLevel, watertoadd );
|
||||
}
|
||||
}
|
||||
|
||||
if ( GetWaterQuality( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) == WATER_POISONOUS )
|
||||
HandlePossibleInfection( pSoldier, NULL, INFECTION_TYPE_BADWATER );
|
||||
|
||||
INT32 bpadded = 100 * min( 20, 100 - pSoldier->bBreath );
|
||||
|
||||
DeductPoints( pSoldier, 20, -bpadded );
|
||||
|
||||
// play water sound
|
||||
if ( pSoldier->bTeam == gbPlayerNum && gGameExternalOptions.fFoodEatingSounds )
|
||||
{
|
||||
PlayJA2SampleFromFile( "Sounds\\watertap.wav", RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
||||
}
|
||||
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[8], pSoldier->GetName( ) );
|
||||
}
|
||||
@@ -107,4 +107,6 @@ void SoldierAutoFillCanteens(SOLDIERTYPE *pSoldier);
|
||||
|
||||
BOOLEAN HasFoodInInventory( SOLDIERTYPE *pSoldier, BOOLEAN fCheckFood, BOOLEAN fCheckDrink );
|
||||
|
||||
void DrinkFromWaterTap( SOLDIERTYPE *pSoldier );
|
||||
|
||||
#endif
|
||||
|
||||
+246
-11
@@ -72,6 +72,10 @@
|
||||
#include <fstream> // added by Flugente
|
||||
#include "DisplayCover.h" // added by Flugente
|
||||
#include "Queen Command.h" // added by Flugente for FindUnderGroundSector(...)
|
||||
#include "LuaInitNPCs.h" // added by Flugente
|
||||
#include "finances.h" // added by Flugente
|
||||
#include "LaptopSave.h" // added by Flugente
|
||||
#include "Game Clock.h" // added by Flugente
|
||||
#include <vfs/Core/vfs_file_raii.h> // added by Flugente for vfs-stuff
|
||||
#endif
|
||||
|
||||
@@ -246,11 +250,11 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa
|
||||
// "attached weapon"
|
||||
pSoldier->usAttackingWeapon = usHandItem;
|
||||
|
||||
// sevenfm: set shift flag for auto-taking of next item from inventory
|
||||
if( fFromUI && _KeyDown(SHIFT) )
|
||||
gfShiftBombPlant = TRUE;
|
||||
else
|
||||
gfShiftBombPlant = FALSE;
|
||||
// sevenfm: set shift flag for auto-taking of next item from inventory
|
||||
if( fFromUI && _KeyDown(SHIFT) )
|
||||
gfShiftBombPlant = TRUE;
|
||||
else
|
||||
gfShiftBombPlant = FALSE;
|
||||
|
||||
// Find soldier flags depend on if it's our own merc firing or a NPC
|
||||
//if ( FindSoldier( sGridNo, &usSoldierIndex, &uiMercFlags, FIND_SOLDIER_GRIDNO ) )
|
||||
@@ -325,7 +329,90 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa
|
||||
return( ITEM_HANDLE_REFUSAL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INT32 usMapPos;
|
||||
GetMouseMapPos( &usMapPos );
|
||||
|
||||
// Flugente: interactive actions
|
||||
if ( Item[usHandItem].ubCursor == INVALIDCURS || usHandItem == NONE )
|
||||
{
|
||||
UINT16 structindex;
|
||||
UINT16 possibleaction = InteractiveActionPossibleAtGridNo( usMapPos, pSoldier->pathing.bLevel, structindex );
|
||||
if ( possibleaction )//&& pSoldier->GetInteractiveActionSkill( usMapPos, pSoldier->pathing.bLevel, possibleaction ) )
|
||||
{
|
||||
// ATE: AI CANNOT GO THROUGH HERE!
|
||||
BOOLEAN fHadToUseCursorPos = FALSE;
|
||||
|
||||
// See if we can get there to stab
|
||||
sActionGridNo = FindAdjacentGridEx( pSoldier, usMapPos, &ubDirection, &sAdjustedGridNo, TRUE, FALSE );
|
||||
if ( sActionGridNo == NOWHERE )
|
||||
{
|
||||
// Try another location...
|
||||
sActionGridNo = FindAdjacentGridEx( pSoldier, sGridNo, &ubDirection, &sAdjustedGridNo, TRUE, FALSE );
|
||||
|
||||
if ( sActionGridNo == NOWHERE )
|
||||
{
|
||||
return(ITEM_HANDLE_CANNOT_GETTO_LOCATION);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate AP costs...
|
||||
sAPCost = 0;//GetAPsToHandcuff( pSoldier, sActionGridNo );
|
||||
sAPCost += PlotPath( pSoldier, sActionGridNo, NO_COPYROUTE, FALSE, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints );
|
||||
|
||||
if ( EnoughPoints( pSoldier, sAPCost, 0, fFromUI ) )
|
||||
{
|
||||
// OK, set UI
|
||||
SetUIBusy( pSoldier->ubID );
|
||||
|
||||
// CHECK IF WE ARE AT THIS GRIDNO NOW
|
||||
if ( pSoldier->sGridNo != sActionGridNo )
|
||||
{
|
||||
// SEND PENDING ACTION
|
||||
pSoldier->aiData.ubPendingAction = MERC_INTERACTIVEACTION;
|
||||
|
||||
if ( fHadToUseCursorPos )
|
||||
{
|
||||
pSoldier->aiData.sPendingActionData2 = usMapPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pTargetSoldier != NULL )
|
||||
{
|
||||
pSoldier->aiData.sPendingActionData2 = pTargetSoldier->sGridNo;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSoldier->aiData.sPendingActionData2 = sGridNo;
|
||||
}
|
||||
}
|
||||
|
||||
pSoldier->aiData.bPendingActionData3 = (INT8)(possibleaction);
|
||||
pSoldier->aiData.ubPendingActionAnimCount = 0;
|
||||
|
||||
// WALK UP TO DEST FIRST
|
||||
pSoldier->EVENT_InternalGetNewSoldierPath( sActionGridNo, pSoldier->usUIMovementMode, FALSE, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
pSoldier->EVENT_SoldierInteractiveAction( sAdjustedGridNo, possibleaction );
|
||||
|
||||
UnSetUIBusy( pSoldier->ubID );
|
||||
}
|
||||
|
||||
if ( fFromUI )
|
||||
{
|
||||
guiPendingOverrideEvent = A_CHANGE_TO_MOVE;
|
||||
}
|
||||
|
||||
return(ITEM_HANDLE_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
return(ITEM_HANDLE_NOAPS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check HAND ITEM
|
||||
@@ -1236,11 +1323,8 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa
|
||||
if ( gGameExternalOptions.fAllowPrisonerSystem && HasItemFlag( usHandItem, HANDCUFFS ) && pTargetSoldier && pTargetSoldier->CanBeCaptured( ) )
|
||||
{
|
||||
// ATE: AI CANNOT GO THROUGH HERE!
|
||||
INT32 usMapPos;
|
||||
BOOLEAN fHadToUseCursorPos = FALSE;
|
||||
|
||||
GetMouseMapPos( &usMapPos );
|
||||
|
||||
// See if we can get there to stab
|
||||
sActionGridNo = FindAdjacentGridEx( pSoldier, sGridNo, &ubDirection, &sAdjustedGridNo, TRUE, FALSE );
|
||||
if ( sActionGridNo == -1 )
|
||||
@@ -1319,11 +1403,8 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa
|
||||
if ( ItemCanBeAppliedToOthers( usHandItem ) )
|
||||
{
|
||||
// ATE: AI CANNOT GO THROUGH HERE!
|
||||
INT32 usMapPos;
|
||||
BOOLEAN fHadToUseCursorPos = FALSE;
|
||||
|
||||
GetMouseMapPos( &usMapPos );
|
||||
|
||||
// See if we can get there to stab
|
||||
sActionGridNo = FindAdjacentGridEx( pSoldier, sGridNo, &ubDirection, &sAdjustedGridNo, TRUE, FALSE );
|
||||
if ( sActionGridNo == -1 )
|
||||
@@ -8696,3 +8777,157 @@ void HandleTakeNewBombFromInventory(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj)
|
||||
pSoldier->TakeNewBombFromInventory(pObj->usItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: interactive actions
|
||||
void DoInteractiveAction( INT32 sGridNo, SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
// we need a valid soldier and a valid object
|
||||
if ( !pSoldier )
|
||||
return;
|
||||
|
||||
// needs to be a valid location
|
||||
if ( TileIsOutOfBounds( sGridNo ) )
|
||||
return;
|
||||
|
||||
UINT16 structindex;
|
||||
UINT16 possibleaction = InteractiveActionPossibleAtGridNo( sGridNo, pSoldier->pathing.bLevel, structindex );
|
||||
|
||||
UINT16 skill = pSoldier->GetInteractiveActionSkill( sGridNo, pSoldier->pathing.bLevel, possibleaction );
|
||||
|
||||
INT32 difficulty = gInteractiveStructure[structindex].difficulty;
|
||||
INT32 luaactionid = gInteractiveStructure[structindex].luaactionid;
|
||||
|
||||
// play sounds
|
||||
switch ( possibleaction )
|
||||
{
|
||||
case INTERACTIVE_STRUCTURE_HACKABLE:
|
||||
PlayJA2SampleFromFile( "Sounds\\keyboard_typing.wav", RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
||||
break;
|
||||
|
||||
case INTERACTIVE_STRUCTURE_READFILE:
|
||||
PlayJA2SampleFromFile( "Sounds\\book_pageturn1.wav", RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( possibleaction == INTERACTIVE_STRUCTURE_HACKABLE )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[0], pSoldier->GetName( ) );
|
||||
|
||||
// hacking is a multiturn-action - we only start the action here, the result is handled elsewhere
|
||||
pSoldier->StartMultiTurnAction( MTA_HACK, sGridNo );
|
||||
}
|
||||
// call lua with the action id - perhaps we might do something special here
|
||||
else if ( luaactionid >= 0 )
|
||||
{
|
||||
LuaHandleInteractiveActionResult( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, sGridNo, pSoldier->pathing.bLevel, pSoldier->ubID, possibleaction, luaactionid, difficulty, skill );
|
||||
}
|
||||
else
|
||||
{
|
||||
DoInteractiveActionDefaultResult( sGridNo, pSoldier->ubID, (skill >= difficulty) );
|
||||
}
|
||||
}
|
||||
|
||||
// handle the default result of an interactive action
|
||||
// This is called either if no lua action id is set, or by lua if this should happen as a supplement to whatever lua does
|
||||
void DoInteractiveActionDefaultResult( INT32 sGridNo, UINT8 ubID, BOOLEAN aSuccess )
|
||||
{
|
||||
SOLDIERTYPE* pSoldier = NULL;
|
||||
if ( ubID != NOBODY )
|
||||
pSoldier = MercPtrs[ubID];
|
||||
|
||||
// we need a valid soldier and a valid object
|
||||
if ( !pSoldier )
|
||||
return;
|
||||
|
||||
// needs to be a valid location
|
||||
if ( TileIsOutOfBounds( sGridNo ) )
|
||||
return;
|
||||
|
||||
UINT16 structindex;
|
||||
UINT16 possibleaction = InteractiveActionPossibleAtGridNo( sGridNo, pSoldier->pathing.bLevel, structindex );
|
||||
|
||||
switch ( possibleaction )
|
||||
{
|
||||
case INTERACTIVE_STRUCTURE_HACKABLE:
|
||||
{
|
||||
if ( aSuccess )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[1], pSoldier->GetName( ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[2], pSoldier->GetName( ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case INTERACTIVE_STRUCTURE_READFILE:
|
||||
{
|
||||
if ( aSuccess )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[3], pSoldier->GetName( ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[4], pSoldier->GetName( ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case INTERACTIVE_STRUCTURE_WATERTAP:
|
||||
{
|
||||
if ( aSuccess )
|
||||
{
|
||||
DrinkFromWaterTap( pSoldier );
|
||||
}
|
||||
else
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[5], pSoldier->GetName( ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case INTERACTIVE_STRUCTURE_SODAMACHINE:
|
||||
{
|
||||
static UINT16 usSodaIndex = 1741;
|
||||
|
||||
// we still have to determine whether a soda item exists, and whether we can pay for it
|
||||
if ( aSuccess )
|
||||
{
|
||||
aSuccess = FALSE;
|
||||
|
||||
// determine soda item, only if this exists can we proceed to sell one
|
||||
if ( HasItemFlag( usSodaIndex, SODA ) || GetFirstItemWithFlag( &usSodaIndex, SODA ) )
|
||||
{
|
||||
if ( LaptopSaveInfo.iCurrentBalance >= Item[usSodaIndex].usPrice )
|
||||
{
|
||||
aSuccess = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( aSuccess )
|
||||
{
|
||||
if ( CreateItem( usSodaIndex, 100, &gTempObject ) && AutoPlaceObjectAnywhere( pSoldier, &gTempObject, TRUE ) )
|
||||
{
|
||||
AddTransactionToPlayersBook( TRANSFER_FUNDS_TO_MERC, pSoldier->ubProfile, GetWorldTotalMin( ), Item[usSodaIndex].usPrice );
|
||||
|
||||
PlayJA2SampleFromFile( "Sounds\\soda_machine.wav", RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
||||
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[6], pSoldier->GetName( ), Item[usSodaIndex].szItemName );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[7], pSoldier->GetName( ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,52 @@ typedef struct {
|
||||
|
||||
extern STRUCTURE_CONSTRUCT gStructureConstruct[STRUCTURE_CONSTRUCT_MAX];
|
||||
|
||||
// Flugente: we can define what structures we can interact with (example: we can hack computers or retrieve information from a file cabinet)
|
||||
typedef enum
|
||||
{
|
||||
INTERACTIVE_STRUCTURE_NO_ACTION,
|
||||
|
||||
INTERACTIVE_STRUCTURE_HACKABLE,
|
||||
INTERACTIVE_STRUCTURE_READFILE,
|
||||
INTERACTIVE_STRUCTURE_WATERTAP,
|
||||
INTERACTIVE_STRUCTURE_SODAMACHINE,
|
||||
|
||||
INTERACTIVE_STRUCTURE_TYPE_MAX,
|
||||
} INTERACTIVE_STRUCTURE_TYPE;
|
||||
|
||||
typedef struct INTERACTIVE_STRUCTURE {
|
||||
void reset()
|
||||
{
|
||||
sector = -1;
|
||||
sectorlevel = -1;
|
||||
tileindexvector.clear( );
|
||||
gridnovector.clear( );
|
||||
sLevel = -1;
|
||||
sActionType = INTERACTIVE_STRUCTURE_NO_ACTION;
|
||||
difficulty = 0;
|
||||
luaactionid = -1;
|
||||
}
|
||||
|
||||
INT16 sector;
|
||||
INT8 sectorlevel; // whether this is on the surface (0) or below (1-3)
|
||||
char szTileSetName[20]; // name of the tileset
|
||||
std::vector<UINT16> tileindexvector; // possible indizes in tileset
|
||||
|
||||
// We can either specify a specific location, or simply leave this empty
|
||||
// in that case, this action will apply to all locations fitting the above criteria, but a specific location definition always takes preference
|
||||
std::vector<INT32> gridnovector; // possible gridnos
|
||||
INT8 sLevel;
|
||||
|
||||
UINT16 sActionType; // one of INTERACTIVE_STRUCTURE_TYPE
|
||||
INT32 difficulty;
|
||||
INT32 luaactionid; // call lua with this ID after performing the usual action - perhaps something special has to happen
|
||||
} INTERACTIVE_STRUCTURE;
|
||||
|
||||
#define INTERACTIVE_STRUCTURE_MAX 200
|
||||
|
||||
extern INTERACTIVE_STRUCTURE gInteractiveStructure[INTERACTIVE_STRUCTURE_MAX];
|
||||
extern UINT32 gMaxInteractiveStructureRead;
|
||||
|
||||
class SOLDIERTYPE;
|
||||
INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHandItem, BOOLEAN fFromUI );
|
||||
void SoldierPickupItem( SOLDIERTYPE *pSoldier, INT32 iItemIndex, INT32 sGridNo, INT8 bZLevel );
|
||||
@@ -253,4 +299,8 @@ INT32 GetFirstObjectInSectorPosition( UINT16 ausItem );
|
||||
|
||||
extern ITEM_POOL *gpItemPool;//dnl ch26 210909
|
||||
|
||||
// Flugente: interactive actions
|
||||
void DoInteractiveAction( INT32 sGridNo, SOLDIERTYPE *pSoldier );
|
||||
void DoInteractiveActionDefaultResult( INT32 sGridNo, UINT8 ubID, BOOLEAN aSuccess );
|
||||
|
||||
#endif
|
||||
+39
-4
@@ -4258,6 +4258,26 @@ INT8 DrawUIMovementPath( SOLDIERTYPE *pSoldier, INT32 usMapPos, UINT32 uiFlags )
|
||||
gsUIHandleShowMoveGridLocation = sActionGridNo;
|
||||
}
|
||||
}
|
||||
else if ( uiFlags == MOVEUI_TARGET_INTERACTIVEACTION )
|
||||
{
|
||||
sActionGridNo = FindAdjacentGridEx( pSoldier, usMapPos, &ubDirection, NULL, FALSE, TRUE );
|
||||
if ( sActionGridNo == -1 )
|
||||
{
|
||||
sActionGridNo = usMapPos;
|
||||
}
|
||||
|
||||
UINT16 structindex;
|
||||
UINT16 possibleaction = InteractiveActionPossibleAtGridNo( usMapPos, pSoldier->pathing.bLevel, structindex );
|
||||
|
||||
sAPCost = GetAPsForInteractiveAction( pSoldier, possibleaction );
|
||||
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;
|
||||
@@ -4600,6 +4620,23 @@ BOOLEAN UIMouseOnValidAttackLocation( SOLDIERTYPE *pSoldier )
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
if ( ubItemCursor == INTERACTIVEACTIONCURS )
|
||||
{
|
||||
if ( gfUIFullTargetFound )
|
||||
{
|
||||
usMapPos = MercPtrs[gusUIFullTargetID]->sGridNo;
|
||||
}
|
||||
|
||||
UINT16 structindex;
|
||||
UINT16 possibleaction = InteractiveActionPossibleAtGridNo( usMapPos, pSoldier->pathing.bLevel, structindex );
|
||||
if ( possibleaction )//&& pSoldier->GetInteractiveActionSkill( usMapPos, pSoldier->pathing.bLevel, possibleaction ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( ubItemCursor == HANDCUFFCURS )
|
||||
{
|
||||
if ( HasItemFlag( (&(pSoldier->inv[HANDPOS]))->usItem, HANDCUFFS ) )
|
||||
@@ -6435,8 +6472,7 @@ INT8 UIHandleInteractiveTilesAndItemsOnTerrain( SOLDIERTYPE *pSoldier, INT32 usM
|
||||
STRUCTURE *pStructure = NULL;
|
||||
BOOLEAN fPoolContainsHiddenItems = FALSE;
|
||||
SOLDIERTYPE *pTSoldier;
|
||||
|
||||
|
||||
|
||||
if ( gfResetUIItemCursorOptimization )
|
||||
{
|
||||
gfResetUIItemCursorOptimization = FALSE;
|
||||
@@ -6677,9 +6713,8 @@ INT8 UIHandleInteractiveTilesAndItemsOnTerrain( SOLDIERTYPE *pSoldier, INT32 usM
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ( pIntTile == NULL )
|
||||
{
|
||||
return( 0 );
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define MOVEUI_TARGET_FORTIFICATION 13
|
||||
#define MOVEUI_TARGET_HANDCUFF 14
|
||||
#define MOVEUI_TARGET_APPLYITEM 15
|
||||
#define MOVEUI_TARGET_INTERACTIVEACTION 16
|
||||
|
||||
#define MOVEUI_RETURN_ON_TARGET_MERC 1
|
||||
|
||||
|
||||
@@ -218,6 +218,18 @@ UICursor gUICursors[ NUM_UI_CURSORS ] =
|
||||
APPLYITEM_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_APPLYITEM, 0,
|
||||
APPLYITEM_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_APPLYITEM_RED, 0,
|
||||
|
||||
HACK_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_HACK, 0,
|
||||
HACK_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_HACK_RED, 0,
|
||||
|
||||
READFILE_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_READFILE, 0,
|
||||
READFILE_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_READFILE_RED, 0,
|
||||
|
||||
WATERTAP_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_WATERTAP, 0,
|
||||
WATERTAP_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_WATERTAP_RED, 0,
|
||||
|
||||
SODAMACHINE_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_SODAMACHINE, 0,
|
||||
SODAMACHINE_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_SODAMACHINE_RED, 0,
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -195,6 +195,18 @@ typedef enum
|
||||
APPLYITEM_GREY_UICURSOR,
|
||||
APPLYITEM_RED_UICURSOR,
|
||||
|
||||
HACK_GREY_UICURSOR,
|
||||
HACK_RED_UICURSOR,
|
||||
|
||||
READFILE_GREY_UICURSOR,
|
||||
READFILE_RED_UICURSOR,
|
||||
|
||||
WATERTAP_GREY_UICURSOR,
|
||||
WATERTAP_RED_UICURSOR,
|
||||
|
||||
SODAMACHINE_GREY_UICURSOR,
|
||||
SODAMACHINE_RED_UICURSOR,
|
||||
|
||||
NUM_UI_CURSORS
|
||||
|
||||
} UICursorDefines;
|
||||
|
||||
@@ -197,7 +197,8 @@ enum {
|
||||
BG_DISLIKEBG, // dislike any other background that has the negative of this value set
|
||||
BG_SMOKERTYPE, // 0: doesnt care about smoking 1: will consume cigarettes, dislikes non-smokers 2: will refuse to smoke, dislikes smokers
|
||||
BG_CROUCHEDDEFENSE, // lowers enemy cth if they fire at us while we are crouched against cover in the direction the shots come from
|
||||
BG_FORTIFY_ASSIGNMENT, // modifies effectivity of 'FORTIFICATION' assignemnt
|
||||
BG_FORTIFY_ASSIGNMENT, // modifies effectivity of 'FORTIFICATION' assignment
|
||||
BG_HACKERSKILL, // hacking skill from 0 to 100, > 0 means hacking is possible
|
||||
|
||||
BG_MAX,
|
||||
};
|
||||
|
||||
@@ -176,6 +176,7 @@ typedef enum ATTACHMENT_SLOT{
|
||||
#define FORTICURS 24
|
||||
#define HANDCUFFCURS 25
|
||||
#define APPLYITEMCURS 26
|
||||
#define INTERACTIVEACTIONCURS 27
|
||||
|
||||
#define CAMERARANGE 10
|
||||
|
||||
@@ -763,7 +764,7 @@ extern OBJECTTYPE gTempObject;
|
||||
#define TRIPWIREROLL 0x01000000 //16777216 // this item is a tripwire roll
|
||||
#define RADIO_SET 0x02000000 //33554432 // item can be used to radio militia/squads in other sectors
|
||||
#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 SODA 0x08000000 //134217728 // item is a can of soda, sold in vending machines
|
||||
|
||||
#define ROOF_COLLAPSE_ITEM 0x10000000 //268435456 // this item is required in the collapsing of roof tiles. It is used internally and should never be seen by the player
|
||||
#define DISEASEPROTECTION_1 0x20000000 //536870912 // this item protects us from getting diseases by human contact if kept in inventory
|
||||
@@ -1138,6 +1139,9 @@ typedef struct
|
||||
UINT8 DisarmModifier;
|
||||
INT8 RepairModifier;
|
||||
|
||||
// Flugente: a modifier to hacking
|
||||
UINT8 usHackingModifier;
|
||||
|
||||
// Flugente: advanced repair/dirt system
|
||||
UINT8 usDamageChance; // chance that damage to the status will also damage the repair threshold
|
||||
FLOAT dirtIncreaseFactor; // one shot causes this much dirt on a gun
|
||||
|
||||
+10
-2
@@ -1382,6 +1382,10 @@ BOOLEAN ExecuteOverhead( )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: we are doing something here - stop multi-turn-action
|
||||
pSoldier->CancelMultiTurnAction( FALSE );
|
||||
|
||||
if ( pSoldier->aiData.ubPendingAction == MERC_PICKUPITEM )
|
||||
{
|
||||
sGridNo = pSoldier->aiData.sPendingActionData2;
|
||||
@@ -1538,6 +1542,11 @@ BOOLEAN ExecuteOverhead( )
|
||||
pSoldier->EVENT_SoldierBeginGiveItem( );
|
||||
pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION;
|
||||
}
|
||||
else if ( pSoldier->aiData.ubPendingAction == MERC_INTERACTIVEACTION )
|
||||
{
|
||||
pSoldier->EVENT_SoldierInteractiveAction( pSoldier->aiData.sPendingActionData2, pSoldier->aiData.bPendingActionData3 );
|
||||
pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION;
|
||||
}
|
||||
|
||||
if ( fNoAPsForPendingAction )
|
||||
{
|
||||
@@ -1547,8 +1556,7 @@ BOOLEAN ExecuteOverhead( )
|
||||
pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
|
||||
pSoldier->ubPendingDirection = NO_PENDING_DIRECTION;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// OK, ADJUST TO STANDING, WE ARE DONE
|
||||
|
||||
@@ -4000,6 +4000,9 @@ INT16 GetAPsForMultiTurnAction( SOLDIERTYPE *pSoldier, UINT8 usActionType )
|
||||
case MTA_REMOVE_FORTIFY:
|
||||
sAPCost += APBPConstants[AP_REMOVE_FORTIFICATION];
|
||||
break;
|
||||
case MTA_HACK:
|
||||
sAPCost += APBPConstants[AP_HACK];
|
||||
break;
|
||||
}
|
||||
|
||||
if ( usActionType == MTA_FORTIFY || usActionType == MTA_REMOVE_FORTIFY )
|
||||
@@ -4010,6 +4013,32 @@ INT16 GetAPsForMultiTurnAction( SOLDIERTYPE *pSoldier, UINT8 usActionType )
|
||||
return sAPCost;
|
||||
}
|
||||
|
||||
INT16 GetAPsForInteractiveAction( SOLDIERTYPE *pSoldier, UINT8 usActionType )
|
||||
{
|
||||
INT16 sAPCost = 0;
|
||||
|
||||
switch ( usActionType )
|
||||
{
|
||||
case INTERACTIVE_STRUCTURE_HACKABLE:
|
||||
sAPCost = GetAPsForMultiTurnAction( pSoldier, MTA_HACK );
|
||||
break;
|
||||
case INTERACTIVE_STRUCTURE_READFILE:
|
||||
sAPCost += APBPConstants[AP_READFILE];
|
||||
break;
|
||||
case INTERACTIVE_STRUCTURE_WATERTAP:
|
||||
sAPCost += APBPConstants[AP_WATERTAP];
|
||||
break;
|
||||
case INTERACTIVE_STRUCTURE_SODAMACHINE:
|
||||
sAPCost += APBPConstants[AP_SODAMACHINE];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return sAPCost;
|
||||
}
|
||||
|
||||
INT16 GetAPsToJumpOver( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
// -25% APs needed to for MA traits
|
||||
|
||||
@@ -356,6 +356,8 @@ INT16 GetAPsToHandcuff( SOLDIERTYPE *pSoldier, INT32 usMapPos ); // added by Flu
|
||||
INT16 GetAPsToApplyItem( SOLDIERTYPE *pSoldier, INT32 usMapPos ); // added by Flugente
|
||||
INT16 GetAPsForMultiTurnAction( SOLDIERTYPE *pSoldier, UINT8 usActionType ); // added by Flugente
|
||||
|
||||
INT16 GetAPsForInteractiveAction( SOLDIERTYPE *pSoldier, UINT8 usActionType ); // added by Flugente
|
||||
|
||||
INT16 GetAPsToJumpOver( SOLDIERTYPE *pSoldier );
|
||||
|
||||
void GetAPChargeForShootOrStabWRTGunRaises( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, BOOLEAN *pfChargeTurning, BOOLEAN *pfChargeRaise, INT16 bAimTime );
|
||||
|
||||
+157
-10
@@ -100,6 +100,7 @@
|
||||
#include "Cheats.h" // added by Flugente
|
||||
#include "MilitiaIndividual.h" // added by Flugente
|
||||
#include "Arms Dealer Init.h" // added by Flugente for armsDealerInfo[]
|
||||
#include "LuaInitNPCs.h" // added by Flugente
|
||||
#endif
|
||||
|
||||
#include "ub_config.h"
|
||||
@@ -16262,12 +16263,13 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( )
|
||||
{
|
||||
case MTA_FORTIFY:
|
||||
case MTA_REMOVE_FORTIFY:
|
||||
// building on a roof is forbidden! stop this!
|
||||
|
||||
/*// building on a roof is forbidden! stop this!
|
||||
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 )
|
||||
@@ -16275,11 +16277,15 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( )
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
default: // default: exit
|
||||
{
|
||||
CancelMultiTurnAction( FALSE );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
case MTA_HACK:
|
||||
break;
|
||||
|
||||
default: // default: exit
|
||||
{
|
||||
CancelMultiTurnAction( FALSE );
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -16289,12 +16295,17 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( )
|
||||
// determine the gridno before us and the item we have in our main hand, this is enough for the current actions
|
||||
OBJECTTYPE* pObj = &(this->inv[HANDPOS]);
|
||||
|
||||
// error if the gridno we started working on is not the gridno we are currently looking at
|
||||
// error if object is missing
|
||||
if ( usMultiTurnAction == MTA_FORTIFY || usMultiTurnAction == MTA_REMOVE_FORTIFY )
|
||||
{
|
||||
if ( !pObj || !(pObj->exists( )) )
|
||||
fActionStillValid = FALSE;
|
||||
else if ( this->sMTActionGridNo != NewGridNo( this->sGridNo, DirectionInc( this->ubDirection ) ) )
|
||||
}
|
||||
|
||||
// error if the gridno we started working on is not the gridno we are currently looking at
|
||||
if ( usMultiTurnAction == MTA_FORTIFY || usMultiTurnAction == MTA_REMOVE_FORTIFY )//|| usMultiTurnAction == MTA_HACK )
|
||||
{
|
||||
if ( this->sMTActionGridNo != NewGridNo( this->sGridNo, DirectionInc( this->ubDirection ) ) )
|
||||
fActionStillValid = FALSE;
|
||||
}
|
||||
|
||||
@@ -16320,7 +16331,7 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( )
|
||||
}
|
||||
break;
|
||||
|
||||
case MTA_REMOVE_FORTIFY:
|
||||
case MTA_REMOVE_FORTIFY:
|
||||
{
|
||||
entireapcost = GetAPsForMultiTurnAction( this, MTA_REMOVE_FORTIFY );
|
||||
entirebpcost = APBPConstants[BP_REMOVE_FORTIFICATION];
|
||||
@@ -16329,6 +16340,18 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( )
|
||||
fActionStillValid = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case MTA_HACK:
|
||||
{
|
||||
entireapcost = GetAPsForMultiTurnAction( this, MTA_HACK );
|
||||
entirebpcost = 0; // hacking isn't exactly hard to do physically :-)
|
||||
|
||||
UINT16 structindex;
|
||||
if ( !this->GetInteractiveActionSkill( this->sMTActionGridNo, this->pathing.bLevel, INTERACTIVE_STRUCTURE_HACKABLE ) ||
|
||||
!InteractiveActionPossibleAtGridNo( this->sMTActionGridNo, this->pathing.bLevel, structindex ) == INTERACTIVE_STRUCTURE_HACKABLE )
|
||||
fActionStillValid = FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !fActionStillValid )
|
||||
@@ -16359,6 +16382,14 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( )
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MTA_HACK:
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// if we can afford it, do it now
|
||||
@@ -16388,6 +16419,31 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( )
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MTA_HACK:
|
||||
{
|
||||
UINT16 structindex;
|
||||
UINT16 possibleaction = InteractiveActionPossibleAtGridNo( this->sMTActionGridNo, this->pathing.bLevel, structindex );
|
||||
UINT16 skill = this->GetInteractiveActionSkill( sGridNo, this->pathing.bLevel, possibleaction );
|
||||
|
||||
INT32 difficulty = gInteractiveStructure[structindex].difficulty;
|
||||
INT32 luaactionid = gInteractiveStructure[structindex].luaactionid;
|
||||
|
||||
BOOLEAN success = (skill >= difficulty);
|
||||
if ( possibleaction != INTERACTIVE_STRUCTURE_HACKABLE )
|
||||
success = FALSE;
|
||||
|
||||
// call lua with the action id - perhaps we might do something special here
|
||||
if ( luaactionid >= 0 )
|
||||
{
|
||||
LuaHandleInteractiveActionResult( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, sGridNo, this->pathing.bLevel, this->ubID, possibleaction, luaactionid, difficulty, skill );
|
||||
}
|
||||
else
|
||||
{
|
||||
DoInteractiveActionDefaultResult( sGridNo, this->ubID, (skill > difficulty) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( entireapcost > 0 )
|
||||
@@ -19174,6 +19230,92 @@ UINT8 SOLDIERTYPE::GetWaterSnakeDefenseChance()
|
||||
return (UINT8)(val);
|
||||
}
|
||||
|
||||
// Flugente: interactive actions
|
||||
UINT16 SOLDIERTYPE::GetInteractiveActionSkill( INT32 sGridNo, UINT8 usLevel, UINT16 usType )
|
||||
{
|
||||
switch ( usType )
|
||||
{
|
||||
case INTERACTIVE_STRUCTURE_HACKABLE:
|
||||
{
|
||||
if ( this->ubProfile == ROBOT || IsVehicle( this ) )
|
||||
return 0;
|
||||
|
||||
UINT16 skill = this->GetBackgroundValue( BG_HACKERSKILL );
|
||||
|
||||
// without the background property, we cannot hack at all
|
||||
if ( !skill )
|
||||
return 0;
|
||||
|
||||
FLOAT bestmodifier = 1.0f;
|
||||
|
||||
UINT8 bestequipmentbonus = 0;
|
||||
|
||||
OBJECTTYPE* pObj = NULL;
|
||||
|
||||
INT8 invsize = (INT8)inv.size( ); // remember inventorysize, so we don't call size() repeatedly
|
||||
|
||||
for ( INT8 bLoop = 0; bLoop < invsize; ++bLoop ) // ... for all items in our inventory ...
|
||||
{
|
||||
// ... if Item exists and is canteen (that can have drink points) ...
|
||||
if ( inv[bLoop].exists( ) == true && Item[inv[bLoop].usItem].usHackingModifier )
|
||||
{
|
||||
OBJECTTYPE * pObj = &(this->inv[bLoop]); // ... get pointer for this item ...
|
||||
|
||||
if ( pObj != NULL ) // ... if pointer is not obviously useless ...
|
||||
{
|
||||
for ( INT16 i = 0; i < pObj->ubNumberOfObjects; ++i )
|
||||
{
|
||||
FLOAT modifier = 1.0f + (Item[inv[bLoop].usItem].usHackingModifier * (*pObj)[i]->data.objectStatus) / 10000.0f;
|
||||
|
||||
if ( modifier > bestmodifier )
|
||||
bestmodifier = modifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (UINT16)(skill * bestmodifier);
|
||||
}
|
||||
break;
|
||||
|
||||
case INTERACTIVE_STRUCTURE_READFILE:
|
||||
{
|
||||
if ( this->ubProfile == ROBOT || IsVehicle( this ) )
|
||||
return 0;
|
||||
|
||||
// reading is governed by wisdom
|
||||
return this->stats.bWisdom;
|
||||
}
|
||||
break;
|
||||
|
||||
case INTERACTIVE_STRUCTURE_WATERTAP:
|
||||
{
|
||||
if ( this->ubProfile == ROBOT || IsVehicle( this ) )
|
||||
return 0;
|
||||
|
||||
// we are pros at drinking water
|
||||
return 100;
|
||||
}
|
||||
break;
|
||||
|
||||
case INTERACTIVE_STRUCTURE_SODAMACHINE:
|
||||
{
|
||||
if ( this->ubProfile == ROBOT || IsVehicle( this ) )
|
||||
return 0;
|
||||
|
||||
// we are pros at buying from a vending machine
|
||||
return 100;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
INT8 bBandaged; //,savedOurTurn;
|
||||
@@ -20275,6 +20417,11 @@ void SOLDIERTYPE::EVENT_SoldierApplyItemToPerson( INT32 sGridNo, UINT8 ubDirecti
|
||||
}
|
||||
}
|
||||
|
||||
void SOLDIERTYPE::EVENT_SoldierInteractiveAction( INT32 sGridNo, UINT16 usActionType )
|
||||
{
|
||||
DoInteractiveAction( sGridNo, this );
|
||||
}
|
||||
|
||||
void SOLDIERTYPE::EVENT_SoldierBeginReloadRobot( INT32 sGridNo, UINT8 ubDirection, UINT8 ubMercSlot )
|
||||
{
|
||||
UINT8 ubPerson;
|
||||
|
||||
@@ -231,6 +231,7 @@ enum
|
||||
MERC_BUILD_FORTIFICATION,
|
||||
MERC_HANDCUFF_PERSON,
|
||||
MERC_APPLYITEM,
|
||||
MERC_INTERACTIVEACTION,
|
||||
};
|
||||
|
||||
// ENUMERATIONS FOR THROW ACTIONS
|
||||
@@ -565,6 +566,7 @@ enum
|
||||
MTA_NONE = 0,
|
||||
MTA_FORTIFY,
|
||||
MTA_REMOVE_FORTIFY,
|
||||
MTA_HACK,
|
||||
NUM_MTA,
|
||||
};
|
||||
|
||||
@@ -1626,6 +1628,7 @@ public:
|
||||
void EVENT_SoldierBuildStructure( INT32 sGridNo, UINT8 ubDirection ); // added by Flugente
|
||||
void EVENT_SoldierHandcuffPerson( INT32 sGridNo, UINT8 ubDirection ); // added by Flugente
|
||||
void EVENT_SoldierApplyItemToPerson( INT32 sGridNo, UINT8 ubDirection ); // added by Flugente
|
||||
void EVENT_SoldierInteractiveAction( INT32 sGridNo, UINT16 usActionType ); // added by Flugente
|
||||
|
||||
BOOLEAN EVENT_InternalGetNewSoldierPath( INT32 sDestGridNo, UINT16 usMovementAnim, BOOLEAN fFromUI, BOOLEAN fForceRestart );
|
||||
void EVENT_InternalSetSoldierDestination( UINT16 usNewDirection, BOOLEAN fFromMove, UINT16 usAnimState );
|
||||
@@ -1935,6 +1938,9 @@ public:
|
||||
|
||||
// Flugente: chance to defeat a water snake instead of being hit by it
|
||||
UINT8 GetWaterSnakeDefenseChance( );
|
||||
|
||||
// Flugente: interactive actions
|
||||
UINT16 GetInteractiveActionSkill( INT32 sGridNo, UINT8 usLevel, UINT16 usType );
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}; // SOLDIERTYPE;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "renderworld.h"
|
||||
#include "strategicmap.h"
|
||||
#include "rotting corpses.h"
|
||||
#include "WorldDat.h" // added by Flugente
|
||||
#endif
|
||||
|
||||
extern BOOLEAN DoesSAMExistHere( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ, INT32 sGridNo );
|
||||
@@ -590,6 +591,135 @@ BOOLEAN IsFortificationPossibleAtGridNo( INT32 sGridNo )
|
||||
return( pStructure == NULL );
|
||||
}
|
||||
|
||||
UINT16 InteractiveActionPossibleAtGridNo( INT32 sGridNo, UINT8 usLevel, UINT16& arusStructIndex )
|
||||
{
|
||||
arusStructIndex = 0;
|
||||
|
||||
STRUCTURE * pStruct = FindStructure( sGridNo, (STRUCTURE_GENERIC) );
|
||||
if ( pStruct )
|
||||
{
|
||||
// if this is a multi-tile structure, be sure to use the base gridno
|
||||
if ( !(pStruct->fFlags & STRUCTURE_BASE_TILE) )
|
||||
{
|
||||
pStruct = FindBaseStructure( pStruct );
|
||||
|
||||
if ( !pStruct )
|
||||
return INTERACTIVE_STRUCTURE_NO_ACTION;
|
||||
}
|
||||
|
||||
LEVELNODE* pNode = FindLevelNodeBasedOnStructure( pStruct->sGridNo, pStruct );
|
||||
|
||||
if ( pNode )
|
||||
{
|
||||
UINT16 usIndex = pNode->usIndex;
|
||||
UINT32 uiTileType = 0;
|
||||
if ( GetTileType( usIndex, &uiTileType ) )
|
||||
{
|
||||
// we loop over each action and determine whether it fits
|
||||
// multiple actions can fit, we chose whatever fits best
|
||||
// So, for example, we can set computers everywhere to be hackable with a generci result, and then define more precise results on specific computers
|
||||
// Other example: With just oen entry, with neither sector nor location set, we can make all water taps drinkable
|
||||
BOOLEAN foundmatch_precise = FALSE;
|
||||
BOOLEAN foundmatch_sector = FALSE;
|
||||
BOOLEAN foundmatch_any = FALSE;
|
||||
|
||||
UINT8 sector = SECTOR( gWorldSectorX, gWorldSectorY );
|
||||
|
||||
int foundindex = 0;
|
||||
if ( gTilesets[giCurrentTilesetID].TileSurfaceFilenames[uiTileType][0] )
|
||||
{
|
||||
for ( int i = 0; i < gMaxInteractiveStructureRead; ++i )
|
||||
{
|
||||
if ( !_strnicmp( gTilesets[giCurrentTilesetID].TileSurfaceFilenames[uiTileType], gInteractiveStructure[i].szTileSetName, 11 ) )
|
||||
{
|
||||
std::vector<UINT16> tmpvec = gInteractiveStructure[i].tileindexvector;
|
||||
|
||||
std::vector<UINT16>::iterator it = std::find( tmpvec.begin( ), tmpvec.end( ), pStruct->pDBStructureRef->pDBStructure->usStructureNumber );
|
||||
|
||||
if ( it != tmpvec.end( ) )
|
||||
{
|
||||
if ( gInteractiveStructure[i].sector == sector && gInteractiveStructure[i].sectorlevel == gbWorldSectorZ )
|
||||
{
|
||||
foundmatch_sector = TRUE;
|
||||
foundindex = i;
|
||||
|
||||
if ( gInteractiveStructure[i].sLevel == usLevel || gInteractiveStructure[i].sLevel == -1 )
|
||||
{
|
||||
std::vector<INT32> tmpgridnovec = gInteractiveStructure[i].gridnovector;
|
||||
|
||||
std::vector<INT32>::iterator it_gridno = std::find( tmpgridnovec.begin( ), tmpgridnovec.end( ), pStruct->sGridNo );
|
||||
|
||||
if ( it_gridno != tmpgridnovec.end( ) )
|
||||
{
|
||||
foundmatch_precise = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// some actions cen be defined everywhere
|
||||
else if ( !foundmatch_sector && gInteractiveStructure[i].sector == -1 && gInteractiveStructure[i].sectorlevel == -1 )
|
||||
{
|
||||
foundmatch_any = TRUE;
|
||||
foundindex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// otherwise, check first tileset (GENERIC 1)
|
||||
else if ( gTilesets[0].TileSurfaceFilenames[uiTileType][0] )
|
||||
{
|
||||
for ( int i = 0; i < gMaxInteractiveStructureRead; ++i )
|
||||
{
|
||||
if ( !_strnicmp( gTilesets[0].TileSurfaceFilenames[uiTileType], gInteractiveStructure[i].szTileSetName, 11 ) )
|
||||
{
|
||||
std::vector<UINT16> tmpvec = gInteractiveStructure[i].tileindexvector;
|
||||
|
||||
std::vector<UINT16>::iterator it = std::find( tmpvec.begin( ), tmpvec.end( ), pStruct->pDBStructureRef->pDBStructure->usStructureNumber );
|
||||
|
||||
if ( it != tmpvec.end() )
|
||||
{
|
||||
if ( gInteractiveStructure[i].sector == sector && gInteractiveStructure[i].sectorlevel == gbWorldSectorZ )
|
||||
{
|
||||
foundmatch_sector = TRUE;
|
||||
foundindex = i;
|
||||
|
||||
if ( gInteractiveStructure[i].sLevel == usLevel || gInteractiveStructure[i].sLevel == -1 )
|
||||
{
|
||||
std::vector<INT32> tmpgridnovec = gInteractiveStructure[i].gridnovector;
|
||||
|
||||
std::vector<INT32>::iterator it_gridno = std::find( tmpgridnovec.begin( ), tmpgridnovec.end( ), pStruct->sGridNo );
|
||||
|
||||
if ( it_gridno != tmpgridnovec.end() )
|
||||
{
|
||||
foundmatch_precise = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( !foundmatch_sector && gInteractiveStructure[i].sector == -1 && gInteractiveStructure[i].sectorlevel == -1 )
|
||||
{
|
||||
foundmatch_any = TRUE;
|
||||
foundindex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( foundmatch_any || foundmatch_sector || foundmatch_precise )
|
||||
{
|
||||
arusStructIndex = foundindex;
|
||||
|
||||
return gInteractiveStructure[foundindex].sActionType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return INTERACTIVE_STRUCTURE_NO_ACTION;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN IsCutWireFenceAtGridNo( INT32 sGridNo )
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ BOOLEAN IsCutWireFenceAtGridNo( INT32 sGridNo );
|
||||
BOOLEAN IsRepairableStructAtGridNo( INT32 sGridNo, UINT8 *pubID );
|
||||
BOOLEAN IsRefuelableStructAtGridNo( INT32 sGridNo, UINT8 *pubID );
|
||||
BOOLEAN IsFortificationPossibleAtGridNo( INT32 sGridNo ); // added by Flugente
|
||||
|
||||
UINT16 InteractiveActionPossibleAtGridNo( INT32 sGridNo, UINT8 usLevel, UINT16& arusStructIndex ); // added by Flugente
|
||||
|
||||
BOOLEAN IsRoofPresentAtGridNo( INT32 sGridNo );
|
||||
|
||||
|
||||
@@ -1144,6 +1144,10 @@
|
||||
RelativePath=".\XML_IncompatibleAttachments.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\XML_InteractiveTiles.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\XML_ItemAdjustments.cpp"
|
||||
>
|
||||
|
||||
@@ -1146,6 +1146,10 @@
|
||||
RelativePath="XML_IncompatibleAttachments.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="XML_InteractiveTiles.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\XML_ItemAdjustments.cpp"
|
||||
>
|
||||
|
||||
@@ -223,6 +223,7 @@
|
||||
<ClCompile Include="XML_HiddenNames.cpp" />
|
||||
<ClCompile Include="XML_IMPItemChoices.cpp" />
|
||||
<ClCompile Include="XML_IncompatibleAttachments.cpp" />
|
||||
<ClCompile Include="XML_InteractiveTiles.cpp" />
|
||||
<ClCompile Include="XML_ItemAdjustments.cpp" />
|
||||
<ClCompile Include="XML_Keys.cpp" />
|
||||
<ClCompile Include="XML_Launchable.cpp" />
|
||||
|
||||
@@ -562,6 +562,9 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="XML_IncompatibleAttachments.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XML_InteractiveTiles.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XML_Launchable.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
|
||||
@@ -224,6 +224,7 @@
|
||||
<ClCompile Include="XML_HiddenNames.cpp" />
|
||||
<ClCompile Include="XML_IMPItemChoices.cpp" />
|
||||
<ClCompile Include="XML_IncompatibleAttachments.cpp" />
|
||||
<ClCompile Include="XML_InteractiveTiles.cpp" />
|
||||
<ClCompile Include="XML_ItemAdjustments.cpp" />
|
||||
<ClCompile Include="XML_Keys.cpp" />
|
||||
<ClCompile Include="XML_Launchable.cpp" />
|
||||
|
||||
@@ -701,5 +701,8 @@
|
||||
<ClCompile Include="XML_MilitiaIndividual.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XML_InteractiveTiles.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -467,7 +467,7 @@ void EndTurnEvents( void )
|
||||
UINT32 cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
|
||||
for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ++cnt, ++pSoldier)
|
||||
{
|
||||
if ( pSoldier->bActive && pSoldier->stats.bLife > 0 && !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && !( AM_A_ROBOT( pSoldier ) ) )
|
||||
if ( pSoldier->bActive && pSoldier->stats.bLife > 0 )//&& !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && !( AM_A_ROBOT( pSoldier ) ) )
|
||||
{
|
||||
// Flugente: update multi-turn actions
|
||||
pSoldier->UpdateMultiTurnAction();
|
||||
|
||||
+43
-7
@@ -57,6 +57,7 @@ UINT8 HandleTinCanCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorF
|
||||
UINT8 HandleFortificationCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags ); //added by Flugente
|
||||
UINT8 HandleHandcuffCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags ); //added by Flugente
|
||||
UINT8 HandleApplyItemCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags ); //added by Flugente
|
||||
UINT8 HandleHackCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags ); //added by Flugente
|
||||
|
||||
extern BOOLEAN HandleCheckForBadChangeToGetThrough( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pTargetSoldier, INT32 sTargetGridNo , INT8 bLevel );
|
||||
|
||||
@@ -323,11 +324,13 @@ UINT8 GetProperItemCursor( UINT8 ubSoldierID, UINT16 ubItemIndex, INT32 usMapPos
|
||||
ubCursorID = HandleApplyItemCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
||||
break;
|
||||
|
||||
case INVALIDCURS:
|
||||
|
||||
ubCursorID = INVALID_ACTION_UICURSOR;
|
||||
case INTERACTIVEACTIONCURS:
|
||||
ubCursorID = HandleHackCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
||||
break;
|
||||
|
||||
case INVALIDCURS:
|
||||
ubCursorID = INVALID_ACTION_UICURSOR;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !( gTacticalStatus.uiFlags & INCOMBAT ) )
|
||||
@@ -341,12 +344,10 @@ UINT8 GetProperItemCursor( UINT8 ubSoldierID, UINT16 ubItemIndex, INT32 usMapPos
|
||||
PauseRT( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return( ubCursorID );
|
||||
}
|
||||
|
||||
|
||||
// WANNE: Shows the target cursor over the enemy soldier
|
||||
UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEAN fShowAPs, BOOLEAN fRecalc, UINT32 uiCursorFlags )
|
||||
{
|
||||
@@ -2276,6 +2277,27 @@ UINT8 HandleApplyItemCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCurs
|
||||
return( APPLYITEM_RED_UICURSOR );
|
||||
}
|
||||
|
||||
UINT8 HandleHackCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
|
||||
{
|
||||
// DRAW PATH TO GUY
|
||||
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_INTERACTIVEACTION );
|
||||
|
||||
UINT16 structindex;
|
||||
UINT16 possibleaction = InteractiveActionPossibleAtGridNo( sGridNo, pSoldier->pathing.bLevel, structindex );
|
||||
UINT16 skill = pSoldier->GetInteractiveActionSkill( sGridNo, pSoldier->pathing.bLevel, possibleaction );
|
||||
|
||||
if ( possibleaction == INTERACTIVE_STRUCTURE_HACKABLE )
|
||||
return skill ? HACK_GREY_UICURSOR : HACK_RED_UICURSOR;
|
||||
else if ( possibleaction == INTERACTIVE_STRUCTURE_READFILE )
|
||||
return skill ? READFILE_GREY_UICURSOR : READFILE_RED_UICURSOR;
|
||||
else if ( possibleaction == INTERACTIVE_STRUCTURE_WATERTAP )
|
||||
return skill ? WATERTAP_GREY_UICURSOR : WATERTAP_RED_UICURSOR;
|
||||
else if ( possibleaction == INTERACTIVE_STRUCTURE_SODAMACHINE )
|
||||
return skill ? SODAMACHINE_GREY_UICURSOR : SODAMACHINE_RED_UICURSOR;
|
||||
|
||||
return NO_UICURSOR;
|
||||
}
|
||||
|
||||
void HandleEndConfirmCursor( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
UINT16 usInHand;
|
||||
@@ -2784,7 +2806,7 @@ UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier )
|
||||
else
|
||||
return ( TRAJECTORYCURS );
|
||||
}
|
||||
if ( pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO || ( pSoldier->bWeaponMode == WM_AUTOFIRE && Item[pSoldier->inv[HANDPOS].usItem].grenadelauncher ) )
|
||||
else if ( pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO || ( pSoldier->bWeaponMode == WM_AUTOFIRE && Item[pSoldier->inv[HANDPOS].usItem].grenadelauncher ) )
|
||||
{
|
||||
if ( gGameSettings.fOptions [ TOPTION_GL_BURST_CURSOR ] )
|
||||
return( TARGETCURS );
|
||||
@@ -2823,6 +2845,20 @@ UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier )
|
||||
if ( gGameExternalOptions.fAllowPrisonerSystem && HasItemFlag(usInHand, HANDCUFFS) )
|
||||
ubCursor = HANDCUFFCURS;
|
||||
|
||||
// Flugente: interactive actions
|
||||
// we only check whether an action is possible in principle, not whether this particular guy can do it. That way we know an action is possible here even if we can't perform it at the moment.
|
||||
// only do this if the item doesn't already allow us to do something else
|
||||
if ( ubCursor == INVALIDCURS || usInHand == NONE )
|
||||
{
|
||||
INT32 usMapPos = NOWHERE;
|
||||
GetMouseMapPos( &usMapPos );
|
||||
|
||||
UINT16 structindex;
|
||||
UINT16 possibleaction = InteractiveActionPossibleAtGridNo( usMapPos, pSoldier->pathing.bLevel, structindex );
|
||||
if ( possibleaction > INTERACTIVE_STRUCTURE_NO_ACTION )
|
||||
ubCursor = INTERACTIVEACTIONCURS;
|
||||
}
|
||||
|
||||
// Flugente: apply misc items to other soldiers
|
||||
if ( ItemCanBeAppliedToOthers( usInHand ) )
|
||||
{
|
||||
|
||||
@@ -172,6 +172,7 @@ typedef PARSE_STAGE;
|
||||
#define SECTORLEVEL1NAMESFILENAME "Map\\SectorNamesLevel_1.xml"
|
||||
#define SECTORLEVEL2NAMESFILENAME "Map\\SectorNamesLevel_2.xml"
|
||||
#define SECTORLEVEL3NAMESFILENAME "Map\\SectorNamesLevel_3.xml"
|
||||
#define INTERACTIVEACTIONSFILENAME "Map\\InteractiveActions.xml"
|
||||
|
||||
#define GARRISONFILENAME "Army\\GarrisonGroups.xml"
|
||||
#define PATROLFILENAME "Army\\PatrolGroups.xml"
|
||||
@@ -326,6 +327,10 @@ extern BOOLEAN WriteStructureDeconstructStats();
|
||||
extern BOOLEAN ReadInStructureConstructStats(STR fileName);
|
||||
extern BOOLEAN WriteStructureConstructStats();
|
||||
|
||||
// Flugente: interactive actions
|
||||
extern BOOLEAN ReadInInteractiveActionsStats( STR fileName );
|
||||
extern BOOLEAN WriteInteractiveActionsStats( );
|
||||
|
||||
// Flugente: merchants
|
||||
extern BOOLEAN ReadInMerchantStats(STR fileName);
|
||||
extern BOOLEAN WriteMerchantStats();
|
||||
|
||||
@@ -135,6 +135,7 @@ backgroundStartElementHandle(void *userData, const XML_Char *name, const XML_Cha
|
||||
strcmp(name, "smoker" ) == 0 ||
|
||||
strcmp(name, "croucheddefense" ) == 0 ||
|
||||
strcmp(name, "fortify_assignment" ) == 0 ||
|
||||
strcmp(name, "hackerskill" ) == 0 ||
|
||||
strcmp(name, "druguse") == 0 ||
|
||||
strcmp(name, "xenophobic") == 0 ||
|
||||
strcmp(name, "corruptionspread") == 0 ||
|
||||
@@ -579,6 +580,11 @@ backgroundEndElementHandle(void *userData, const XML_Char *name)
|
||||
pData->curElement = ELEMENT;
|
||||
pData->curBackground.value[BG_FORTIFY_ASSIGNMENT] = min( 200, max( -50, (INT16)atol( pData->szCharData ) ) );
|
||||
}
|
||||
else if ( strcmp( name, "hackerskill" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
pData->curBackground.value[BG_HACKERSKILL] = min( 100, max( 0, (INT16)atol( pData->szCharData ) ) );
|
||||
}
|
||||
else if(strcmp(name, "druguse") == 0)
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Flugente (bears-pit.com)
|
||||
*/
|
||||
|
||||
#ifdef PRECOMPILEDHEADERS
|
||||
#include "Tactical All.h"
|
||||
#else
|
||||
#include "sgp.h"
|
||||
#include "Debug Control.h"
|
||||
#include "expat.h"
|
||||
#include "gamesettings.h"
|
||||
#include "XML.h"
|
||||
#include "FileMan.h"
|
||||
#include "Handle Items.h"
|
||||
#endif
|
||||
|
||||
INTERACTIVE_STRUCTURE gInteractiveStructure[INTERACTIVE_STRUCTURE_MAX];
|
||||
UINT32 gMaxInteractiveStructureRead = 0;
|
||||
|
||||
struct
|
||||
{
|
||||
PARSE_STAGE curElement;
|
||||
|
||||
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH + 1];
|
||||
INTERACTIVE_STRUCTURE curFood;
|
||||
INTERACTIVE_STRUCTURE* curArray;
|
||||
|
||||
UINT32 maxArraySize;
|
||||
UINT32 curIndex;
|
||||
UINT32 currentDepth;
|
||||
UINT32 maxReadDepth;
|
||||
}
|
||||
typedef interactiveactionsParseData;
|
||||
|
||||
static void XMLCALL
|
||||
interactiveactionsStartElementHandle( void *userData, const XML_Char *name, const XML_Char **atts )
|
||||
{
|
||||
interactiveactionsParseData * pData = (interactiveactionsParseData *)userData;
|
||||
|
||||
if ( pData->currentDepth <= pData->maxReadDepth ) //are we reading this element?
|
||||
{
|
||||
if ( strcmp( name, "INTERACTIVEACTIONS" ) == 0 && pData->curElement == ELEMENT_NONE )
|
||||
{
|
||||
pData->curElement = ELEMENT_LIST;
|
||||
|
||||
memset( pData->curArray, 0, sizeof(INTERACTIVE_STRUCTURE)*pData->maxArraySize );
|
||||
|
||||
pData->maxReadDepth++; //we are not skipping this element
|
||||
}
|
||||
else if ( strcmp( name, "ACTION" ) == 0 && pData->curElement == ELEMENT_LIST )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
|
||||
memset( &pData->curFood, 0, sizeof(INTERACTIVE_STRUCTURE) );
|
||||
|
||||
pData->curFood.reset( );
|
||||
|
||||
pData->maxReadDepth++; //we are not skipping this element
|
||||
}
|
||||
else if ( pData->curElement == ELEMENT &&
|
||||
(strcmp( name, "SectorGrid" ) == 0 ||
|
||||
strcmp( name, "sectorlevel" ) == 0 ||
|
||||
strcmp( name, "szTileSetName" ) == 0 ||
|
||||
strcmp( name, "usTileIndex" ) == 0 ||
|
||||
strcmp( name, "sStructureGridno" ) == 0 ||
|
||||
strcmp( name, "sLevel" ) == 0 ||
|
||||
strcmp( name, "sActionType" ) == 0 ||
|
||||
strcmp( name, "difficulty" ) == 0 ||
|
||||
strcmp( name, "luaactionid" ) == 0
|
||||
) )
|
||||
{
|
||||
pData->curElement = ELEMENT_PROPERTY;
|
||||
|
||||
pData->maxReadDepth++; //we are not skipping this element
|
||||
}
|
||||
|
||||
pData->szCharData[0] = '\0';
|
||||
}
|
||||
|
||||
pData->currentDepth++;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
interactiveactionsDataHandle( void *userData, const XML_Char *str, int len )
|
||||
{
|
||||
interactiveactionsParseData * pData = (interactiveactionsParseData *)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
|
||||
interactiveactionsEndElementHandle( void *userData, const XML_Char *name )
|
||||
{
|
||||
static std::vector<UINT16> tileindexvector;
|
||||
static std::vector<INT32> gridnovector;
|
||||
|
||||
interactiveactionsParseData * pData = (interactiveactionsParseData *)userData;
|
||||
|
||||
if ( pData->currentDepth <= pData->maxReadDepth ) //we're at the end of an element that we've been reading
|
||||
{
|
||||
if ( strcmp( name, "INTERACTIVEACTIONS" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT_NONE;
|
||||
|
||||
gMaxInteractiveStructureRead = pData->curIndex;
|
||||
}
|
||||
else if ( strcmp( name, "ACTION" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT_LIST;
|
||||
|
||||
if ( pData->curIndex < pData->maxArraySize )
|
||||
{
|
||||
// for whatever reasons the game crashes in VS2008 Release builds when copying over the tilevector
|
||||
// this seems odd, as this works just fine in VS2010 and VS2013, and also works in VS205 debug builds
|
||||
// for now, copy over the content by hand
|
||||
pData->curArray[pData->curIndex].sector = pData->curFood.sector;
|
||||
pData->curArray[pData->curIndex].sectorlevel = pData->curFood.sectorlevel;
|
||||
strncpy( pData->curArray[pData->curIndex].szTileSetName, pData->curFood.szTileSetName, 20 );
|
||||
pData->curArray[pData->curIndex].tileindexvector = tileindexvector;
|
||||
pData->curArray[pData->curIndex].gridnovector = gridnovector;
|
||||
pData->curArray[pData->curIndex].sLevel = pData->curFood.sLevel;
|
||||
pData->curArray[pData->curIndex].sActionType = pData->curFood.sActionType;
|
||||
pData->curArray[pData->curIndex].difficulty = pData->curFood.difficulty;
|
||||
pData->curArray[pData->curIndex].luaactionid = pData->curFood.luaactionid;
|
||||
|
||||
tileindexvector.clear( );
|
||||
tileindexvector.resize( 0 );
|
||||
|
||||
gridnovector.clear();
|
||||
gridnovector.resize( 0 );
|
||||
}
|
||||
|
||||
pData->curIndex++;
|
||||
}
|
||||
|
||||
else if ( strcmp( name, "SectorGrid" ) == 0 )
|
||||
{
|
||||
UINT8 x, y;
|
||||
pData->curElement = ELEMENT;
|
||||
|
||||
y = (UINT8)pData->szCharData[0] & 0x1F;
|
||||
x = (UINT8)atol( &pData->szCharData[1] );
|
||||
if ( x > 0 && x <= 16 && y > 0 && y <= 16 )
|
||||
{
|
||||
pData->curFood.sector = SECTOR(x, y);
|
||||
}
|
||||
}
|
||||
else if ( strcmp( name, "sectorlevel" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
pData->curFood.sectorlevel = min( 3, max(-1, (INT8)atol( pData->szCharData ) ) );
|
||||
}
|
||||
else if ( strcmp( name, "szTileSetName" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
|
||||
strncpy( pData->curFood.szTileSetName, pData->szCharData, 20 );
|
||||
}
|
||||
else if ( strcmp( name, "usTileIndex" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
tileindexvector.push_back( (UINT16)atol( pData->szCharData ) );
|
||||
}
|
||||
else if ( strcmp( name, "sStructureGridno" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
gridnovector.push_back( (INT32)atol( pData->szCharData ) );
|
||||
}
|
||||
else if ( strcmp( name, "sLevel" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
pData->curFood.sLevel = min( 1, max( 0, (INT8)atol( pData->szCharData ) ) );
|
||||
}
|
||||
else if ( strcmp( name, "sActionType" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
pData->curFood.sActionType = (UINT16)atol( pData->szCharData );
|
||||
}
|
||||
else if ( strcmp( name, "difficulty" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
pData->curFood.difficulty = (INT32)atol( pData->szCharData );
|
||||
}
|
||||
else if ( strcmp( name, "luaactionid" ) == 0 )
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
pData->curFood.luaactionid = (INT32)atol( pData->szCharData );
|
||||
}
|
||||
|
||||
pData->maxReadDepth--;
|
||||
}
|
||||
|
||||
pData->currentDepth--;
|
||||
}
|
||||
|
||||
BOOLEAN ReadInInteractiveActionsStats( STR fileName )
|
||||
{
|
||||
HWFILE hFile;
|
||||
UINT32 uiBytesRead;
|
||||
UINT32 uiFSize;
|
||||
CHAR8 * lpcBuffer;
|
||||
XML_Parser parser = XML_ParserCreate( NULL );
|
||||
|
||||
interactiveactionsParseData pData;
|
||||
|
||||
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Loading InteractiveActions.xml" );
|
||||
|
||||
// Open merges 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, interactiveactionsStartElementHandle, interactiveactionsEndElementHandle );
|
||||
XML_SetCharacterDataHandler( parser, interactiveactionsDataHandle );
|
||||
|
||||
memset( &pData, 0, sizeof(pData) );
|
||||
pData.maxArraySize = INTERACTIVE_STRUCTURE_MAX;
|
||||
pData.curIndex = 0;
|
||||
pData.curFood.reset( );
|
||||
pData.curArray = gInteractiveStructure;
|
||||
|
||||
XML_SetUserData( parser, &pData );
|
||||
|
||||
if ( !XML_Parse( parser, lpcBuffer, uiFSize, TRUE ) )
|
||||
{
|
||||
CHAR8 errorBuf[511];
|
||||
|
||||
sprintf( errorBuf, "XML Parser Error in InteractiveActions.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);
|
||||
}
|
||||
@@ -15,7 +15,7 @@ struct
|
||||
|
||||
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
|
||||
STRUCTURE_CONSTRUCT curFood;
|
||||
STRUCTURE_CONSTRUCT * curArray;
|
||||
STRUCTURE_CONSTRUCT* curArray;
|
||||
UINT32 maxArraySize;
|
||||
|
||||
UINT32 currentDepth;
|
||||
|
||||
Reference in New Issue
Block a user