diff --git a/GameSettings.cpp b/GameSettings.cpp index 318d52c7..c85795c1 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -3311,7 +3311,11 @@ void LoadGameAPBPConstants() APBPConstants[AP_APPLYITEM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_APPLYITEM",50),50); APBPConstants[AP_INVENTORY_ARM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_INVENTORY_ARM",50),50); APBPConstants[AP_SPOTTER] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_SPOTTER",20),20); - + APBPConstants[AP_HACK] = DynamicAdjustAPConstants( iniReader.ReadInteger( "APConstants", "AP_HACK", 300 ), 300 ); + APBPConstants[AP_READFILE] = DynamicAdjustAPConstants( iniReader.ReadInteger( "APConstants", "AP_READFILE", 50 ), 50 ); + APBPConstants[AP_WATERTAP] = DynamicAdjustAPConstants( iniReader.ReadInteger( "APConstants", "AP_WATERTAP", 20 ), 20 ); + APBPConstants[AP_SODAMACHINE] = DynamicAdjustAPConstants( iniReader.ReadInteger( "APConstants", "AP_SODAMACHINE", 30 ), 30 ); + APBPConstants[AP_ENTER_VEHICLE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_ENTER_VEHICLE",30),30); APBPConstants[AP_EXIT_VEHICLE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_EXIT_VEHICLE",30),30); APBPConstants[AP_CHANGE_SEAT_VEHICLE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_CHANGE_SEAT_VEHICLE",20),20); diff --git a/GameVersion.cpp b/GameVersion.cpp index 4798679c..debed40b 100644 --- a/GameVersion.cpp +++ b/GameVersion.cpp @@ -15,9 +15,9 @@ #ifdef JA2EDITOR #ifdef JA2UB - CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.8275 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.8278 (Development Build)" }; #else - CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8275 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8278 (Development Build)" }; #endif // ------------------------------ @@ -27,11 +27,11 @@ //DEBUG BUILD VERSION #ifdef JA2UB - CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.8275 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.8278 (Development Build)" }; #elif defined (JA113DEMO) - CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.8275 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.8278 (Development Build)" }; #else - CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8275 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8278 (Development Build)" }; #endif #elif defined CRIPPLED_VERSION @@ -46,16 +46,16 @@ //RELEASE BUILD VERSION #ifdef JA2UB - CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.8275 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.8278 (Development Build)" }; #elif defined (JA113DEMO) - CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.8275 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.8278 (Development Build)" }; #else - CHAR16 zVersionLabel[256] = { L"Release v1.13.8275 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Release v1.13.8278 (Development Build)" }; #endif #endif -CHAR8 czVersionNumber[16] = { "Build 16.07.17" }; //YY.MM.DD +CHAR8 czVersionNumber[16] = { "Build 16.07.31" }; //YY.MM.DD CHAR16 zTrackingNumber[16] = { L"Z" }; // SAVE_GAME_VERSION is defined in header, change it there diff --git a/Init.cpp b/Init.cpp index 5a21aec0..836f803d 100644 --- a/Init.cpp +++ b/Init.cpp @@ -391,6 +391,10 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) strcat(fileName, STRUCTURECONSTRUCTFILENAME); SGP_THROW_IFFALSE(ReadInStructureConstructStats(fileName),STRUCTURECONSTRUCTFILENAME); + strcpy( fileName, directoryName ); + strcat( fileName, INTERACTIVEACTIONSFILENAME ); + SGP_THROW_IFFALSE( ReadInInteractiveActionsStats( fileName ), INTERACTIVEACTIONSFILENAME ); + strcpy(fileName, directoryName); strcat(fileName, MERCHANTSFILENAME); SGP_THROW_IFFALSE(ReadInMerchantStats(fileName),MERCHANTSFILENAME); diff --git a/Init.h b/Init.h index 1d2be6f6..562b873e 100644 --- a/Init.h +++ b/Init.h @@ -154,6 +154,10 @@ AP_HANDCUFF, AP_APPLYITEM, AP_INVENTORY_ARM, AP_SPOTTER, +AP_HACK, +AP_READFILE, +AP_WATERTAP, +AP_SODAMACHINE, AP_ENTER_VEHICLE, AP_EXIT_VEHICLE, diff --git a/Strategic/LuaInitNPCs.cpp b/Strategic/LuaInitNPCs.cpp index 7f4a5356..7a3efd1d 100644 --- a/Strategic/LuaInitNPCs.cpp +++ b/Strategic/LuaInitNPCs.cpp @@ -857,6 +857,9 @@ static int l_SetModderLUAFact( lua_State *L ); static int l_SetScreenMsg( lua_State *L ); static int l_GetUsedLanguage( lua_State *L ); +static int l_DoInteractiveActionDefaultResult( lua_State *L ); +static int l_GiveExp( lua_State *L ); + using namespace std; UINT16 idProfil; @@ -1722,6 +1725,9 @@ void IniFunction(lua_State *L, BOOLEAN bQuests ) lua_register( L, "SetScreenMsg", l_SetScreenMsg ); lua_register( L, "GetUsedLanguage", l_GetUsedLanguage ); + + lua_register( L, "DoInteractiveActionDefaultResult", l_DoInteractiveActionDefaultResult ); + lua_register( L, "GiveExp", l_GiveExp ); } #ifdef NEWMUSIC BOOLEAN LetLuaMusicControl(UINT8 Init) @@ -2648,6 +2654,24 @@ void LuaHandleSectorLiberation( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, B LuaFunction( _LS.L, "HandleSectorLiberation" ).Param( sSectorX ).Param( sSectorY ).Param( bSectorZ ).Param( fFirstTime ).Call( 4 ); } +void LuaHandleInteractiveActionResult( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, + INT32 sGridNo, UINT8 bLevel, UINT8 ubId, + UINT8 usActionType, INT32 sLuaactionid, INT32 difficulty, UINT16 skill ) +{ + const char* filename = "scripts\\Overhead.lua"; + + LuaScopeState _LS( true ); + + lua_register( _LS.L( ), "CheckFact", l_CheckFact ); + lua_register( _LS.L( ), "AddVolunteers", l_AddVolunteers ); + IniFunction( _LS.L( ), TRUE ); + IniGlobalGameSetting( _LS.L( ) ); + + SGP_THROW_IFFALSE( _LS.L.EvalFile( filename ), _BS( "Cannot open file: " ) << filename << _BS::cget ); + + LuaFunction( _LS.L, "HandleInteractiveActionResult" ).Param( sSectorX ).Param( sSectorY ).Param( bSectorZ ).Param( sGridNo ).Param( bLevel ).Param( ubId ).Param( usActionType ).Param( sLuaactionid ).Param( difficulty ).Param( skill ).Call( 10 ); +} + void LuaRecruitRPCAdditionalHandling( UINT8 usProfile ) { const char* filename = "scripts\\strategicmap.lua"; @@ -13241,3 +13265,34 @@ static int l_GetUsedLanguage( lua_State *L ) return 1; } + +static int l_DoInteractiveActionDefaultResult( lua_State *L ) +{ + if ( lua_gettop( L ) >= 3 ) + { + INT32 sGridNo = lua_tointeger( L, 1 ); + UINT8 ubID = lua_tointeger( L, 2 ); + BOOLEAN success = lua_tointeger( L, 3 ); + + DoInteractiveActionDefaultResult( sGridNo, ubID, success ); + } + + return 0; +} + +static int l_GiveExp( lua_State *L ) +{ + if ( lua_gettop( L ) >= 3 ) + { + UINT8 ubID = lua_tointeger( L, 1 ); + UINT8 ubStat = lua_tointeger( L, 2 ); + UINT16 usNumChances = lua_tointeger( L, 3 ); + + if ( ubID != NOBODY && ubStat >= FIRST_CHANGEABLE_STAT && ubStat <= LAST_CHANGEABLE_STAT ) + { + StatChange( MercPtrs[ubID], ubStat, usNumChances, FROM_SUCCESS ); + } + } + + return 0; +} diff --git a/Strategic/LuaInitNPCs.h b/Strategic/LuaInitNPCs.h index ff55b786..617d76c2 100644 --- a/Strategic/LuaInitNPCs.h +++ b/Strategic/LuaInitNPCs.h @@ -60,6 +60,9 @@ extern BOOLEAN LuaHandleQuestCodeOnSector( INT16 sSectorX, INT16 sSectorY, INT8 //extern BOOLEAN LuaHandleQuestCodeOnSectorEntry( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 Init); void LuaHandleSectorLiberation( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, BOOLEAN fFirstTime ); +void LuaHandleInteractiveActionResult( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, + INT32 sGridNo, UINT8 bLevel, UINT8 ubId, + UINT8 usActionType, INT32 sLuaactionid, INT32 difficulty, UINT16 skill ); void LuaRecruitRPCAdditionalHandling( UINT8 usProfile ); void LuaHandleSectorTacticalEntry( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, BOOLEAN fHasEverBeenPlayerControlled ); diff --git a/Tactical/Faces.cpp b/Tactical/Faces.cpp index d968e454..24ffa8cc 100644 --- a/Tactical/Faces.cpp +++ b/Tactical/Faces.cpp @@ -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++; diff --git a/Tactical/Food.cpp b/Tactical/Food.cpp index ae728339..b930ee37 100644 --- a/Tactical/Food.cpp +++ b/Tactical/Food.cpp @@ -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( ) ); } \ No newline at end of file diff --git a/Tactical/Food.h b/Tactical/Food.h index 8c76febc..c0181e02 100644 --- a/Tactical/Food.h +++ b/Tactical/Food.h @@ -107,4 +107,6 @@ void SoldierAutoFillCanteens(SOLDIERTYPE *pSoldier); BOOLEAN HasFoodInInventory( SOLDIERTYPE *pSoldier, BOOLEAN fCheckFood, BOOLEAN fCheckDrink ); +void DrinkFromWaterTap( SOLDIERTYPE *pSoldier ); + #endif diff --git a/Tactical/Handle Items.cpp b/Tactical/Handle Items.cpp index c2ce344c..51fb8cf9 100644 --- a/Tactical/Handle Items.cpp +++ b/Tactical/Handle Items.cpp @@ -72,6 +72,10 @@ #include // 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 // 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; + } +} diff --git a/Tactical/Handle Items.h b/Tactical/Handle Items.h index 32b1ace0..61642417 100644 --- a/Tactical/Handle Items.h +++ b/Tactical/Handle Items.h @@ -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 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 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 \ No newline at end of file diff --git a/Tactical/Handle UI.cpp b/Tactical/Handle UI.cpp index 294be6f0..01870720 100644 --- a/Tactical/Handle UI.cpp +++ b/Tactical/Handle UI.cpp @@ -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 ); diff --git a/Tactical/Handle UI.h b/Tactical/Handle UI.h index af02cca1..9c85d324 100644 --- a/Tactical/Handle UI.h +++ b/Tactical/Handle UI.h @@ -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 diff --git a/Tactical/Interface Cursors.cpp b/Tactical/Interface Cursors.cpp index 21612d16..665f4a50 100644 --- a/Tactical/Interface Cursors.cpp +++ b/Tactical/Interface Cursors.cpp @@ -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, + }; diff --git a/Tactical/Interface Cursors.h b/Tactical/Interface Cursors.h index cd5108e7..f8fb9b89 100644 --- a/Tactical/Interface Cursors.h +++ b/Tactical/Interface Cursors.h @@ -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; diff --git a/Tactical/Interface.h b/Tactical/Interface.h index 4472ffd2..0c21829b 100644 --- a/Tactical/Interface.h +++ b/Tactical/Interface.h @@ -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, }; diff --git a/Tactical/Item Types.h b/Tactical/Item Types.h index 1430e996..1b1cf8cd 100644 --- a/Tactical/Item Types.h +++ b/Tactical/Item Types.h @@ -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 diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index 6ff58d7c..f34ce602 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -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 diff --git a/Tactical/Points.cpp b/Tactical/Points.cpp index 1ce6d4e8..e9c5ccae 100644 --- a/Tactical/Points.cpp +++ b/Tactical/Points.cpp @@ -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 diff --git a/Tactical/Points.h b/Tactical/Points.h index 1c57fd35..cc717453 100644 --- a/Tactical/Points.h +++ b/Tactical/Points.h @@ -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 ); diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 2dda96f4..74adcb33 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -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; diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index 650b1642..d2eb6658 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -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; diff --git a/Tactical/Structure Wrap.cpp b/Tactical/Structure Wrap.cpp index d4b64329..c487c992 100644 --- a/Tactical/Structure Wrap.cpp +++ b/Tactical/Structure Wrap.cpp @@ -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 tmpvec = gInteractiveStructure[i].tileindexvector; + + std::vector::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 tmpgridnovec = gInteractiveStructure[i].gridnovector; + + std::vector::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 tmpvec = gInteractiveStructure[i].tileindexvector; + + std::vector::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 tmpgridnovec = gInteractiveStructure[i].gridnovector; + + std::vector::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 ) { diff --git a/Tactical/Structure Wrap.h b/Tactical/Structure Wrap.h index 37177472..0679e26c 100644 --- a/Tactical/Structure Wrap.h +++ b/Tactical/Structure Wrap.h @@ -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 ); diff --git a/Tactical/Tactical_VS2005.vcproj b/Tactical/Tactical_VS2005.vcproj index 9e4db2f6..f37e1dbb 100644 --- a/Tactical/Tactical_VS2005.vcproj +++ b/Tactical/Tactical_VS2005.vcproj @@ -1144,6 +1144,10 @@ RelativePath=".\XML_IncompatibleAttachments.cpp" > + + diff --git a/Tactical/Tactical_VS2008.vcproj b/Tactical/Tactical_VS2008.vcproj index 27f9af60..77290a64 100644 --- a/Tactical/Tactical_VS2008.vcproj +++ b/Tactical/Tactical_VS2008.vcproj @@ -1146,6 +1146,10 @@ RelativePath="XML_IncompatibleAttachments.cpp" > + + diff --git a/Tactical/Tactical_VS2010.vcxproj b/Tactical/Tactical_VS2010.vcxproj index e47695cb..675b153e 100644 --- a/Tactical/Tactical_VS2010.vcxproj +++ b/Tactical/Tactical_VS2010.vcxproj @@ -223,6 +223,7 @@ + diff --git a/Tactical/Tactical_VS2010.vcxproj.filters b/Tactical/Tactical_VS2010.vcxproj.filters index 1ea1a0be..7b9420ed 100644 --- a/Tactical/Tactical_VS2010.vcxproj.filters +++ b/Tactical/Tactical_VS2010.vcxproj.filters @@ -562,6 +562,9 @@ Source Files + + + Source Files Source Files diff --git a/Tactical/Tactical_VS2013.vcxproj b/Tactical/Tactical_VS2013.vcxproj index 6622f47e..27a71c4e 100644 --- a/Tactical/Tactical_VS2013.vcxproj +++ b/Tactical/Tactical_VS2013.vcxproj @@ -224,6 +224,7 @@ + diff --git a/Tactical/Tactical_VS2013.vcxproj.filters b/Tactical/Tactical_VS2013.vcxproj.filters index d5d63b26..55b87bd2 100644 --- a/Tactical/Tactical_VS2013.vcxproj.filters +++ b/Tactical/Tactical_VS2013.vcxproj.filters @@ -701,5 +701,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Tactical/TeamTurns.cpp b/Tactical/TeamTurns.cpp index 381be6df..39ddd3d6 100644 --- a/Tactical/TeamTurns.cpp +++ b/Tactical/TeamTurns.cpp @@ -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(); diff --git a/Tactical/UI Cursors.cpp b/Tactical/UI Cursors.cpp index 7a432f61..87e52e45 100644 --- a/Tactical/UI Cursors.cpp +++ b/Tactical/UI Cursors.cpp @@ -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 ) ) { diff --git a/Tactical/XML.h b/Tactical/XML.h index 75eb87bc..37326ae9 100644 --- a/Tactical/XML.h +++ b/Tactical/XML.h @@ -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(); diff --git a/Tactical/XML_Background.cpp b/Tactical/XML_Background.cpp index 5c42b471..1d7d509b 100644 --- a/Tactical/XML_Background.cpp +++ b/Tactical/XML_Background.cpp @@ -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; diff --git a/Tactical/XML_InteractiveTiles.cpp b/Tactical/XML_InteractiveTiles.cpp new file mode 100644 index 00000000..a80a0ad1 --- /dev/null +++ b/Tactical/XML_InteractiveTiles.cpp @@ -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 tileindexvector; + static std::vector 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); +} diff --git a/Tactical/XML_StructureConstruct.cpp b/Tactical/XML_StructureConstruct.cpp index 2a42dcd2..65b58018 100644 --- a/Tactical/XML_StructureConstruct.cpp +++ b/Tactical/XML_StructureConstruct.cpp @@ -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; diff --git a/Utils/Cursors.cpp b/Utils/Cursors.cpp index 62566b5d..ed64c5ee 100644 --- a/Utils/Cursors.cpp +++ b/Utils/Cursors.cpp @@ -128,6 +128,18 @@ CursorFileData CursorFileDatabase[] = { "CURSORS\\apply_r.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL }, // Flugente: apply items - still needs animation { "CURSORS\\apply.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL }, // yes, the red one is the 'valid' one - just like for taking items + { "CURSORS\\hack.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, // Flugente: hack + { "CURSORS\\hack_r.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, + + { "CURSORS\\readfile.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, // Flugente: read file + { "CURSORS\\readfile_r.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, + + {"CURSORS\\watertap.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, // Flugente: watertap + {"CURSORS\\watertap_r.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, + + {"CURSORS\\sodamachine.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, // Flugente: soda machine + {"CURSORS\\sodamachine_r.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, + { "CURSORS\\can_01.sti" , FALSE, 0, 0, 0, NULL }, { "CURSORS\\can_02.sti" , FALSE, 0, 0, 0, NULL }, { "CURSORS\\cur_tagr_ncth.sti" , FALSE, 0, ANIMATED_CURSOR, 7, NULL }, @@ -1232,6 +1244,66 @@ CursorData CursorDatabase[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0 , 0, 0 }, + + // Flugente: hack + { C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_HACK, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, + + { C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_HACK_RED, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, + + // Flugente: read file + {C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_READFILE, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, + + {C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_READFILE_RED, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, + + // Flugente: watertap + {C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_WATERTAP, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, + + {C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_WATERTAP_RED, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, + + // Flugente: soad machine + {C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_SODAMACHINE, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, + + {C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_SODAMACHINE_RED, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, { C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, C_FUEL , 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, diff --git a/Utils/Cursors.h b/Utils/Cursors.h index b0bbaf0a..0d3fbf1d 100644 --- a/Utils/Cursors.h +++ b/Utils/Cursors.h @@ -162,6 +162,18 @@ typedef enum CURSOR_APPLYITEM, CURSOR_APPLYITEM_RED, + CURSOR_HACK, + CURSOR_HACK_RED, + + CURSOR_READFILE, + CURSOR_READFILE_RED, + + CURSOR_WATERTAP, + CURSOR_WATERTAP_RED, + + CURSOR_SODAMACHINE, + CURSOR_SODAMACHINE_RED, + CURSOR_FUEL, CURSOR_FUEL_RED, @@ -241,6 +253,14 @@ typedef enum C_HANDCUFFS_RED, C_APPLYITEM, C_APPLYITEM_RED, + C_HACK, + C_HACK_RED, + C_READFILE, + C_READFILE_RED, + C_WATERTAP, + C_WATERTAP_RED, + C_SODAMACHINE, + C_SODAMACHINE_RED, C_FUEL, C_FUEL_RED, C_ACTIONMODERED_NCTH, diff --git a/Utils/Text.h b/Utils/Text.h index 3d8967e6..5f20a158 100644 --- a/Utils/Text.h +++ b/Utils/Text.h @@ -885,6 +885,7 @@ enum STR_MTA_NONE, STR_MTA_FORTIFY, STR_MTA_REMOVE_FORTIFY, + STR_MTA_HACK, STR_MTA_CANCEL, STR_MTA_CANNOT_BUILD, @@ -2977,6 +2978,9 @@ extern STR16 szSnakeText[]; // Flugente: militia resources extern STR16 szSMilitiaResourceText[]; +// Flugente: interactive actions +extern STR16 szInteractiveActionText[]; + #define TACTICAL_INVENTORY_DIALOG_NUM 16 #define TACTICAL_COVER_DIALOG_NUM 16 diff --git a/Utils/XML_Items.cpp b/Utils/XML_Items.cpp index a7f98d22..6dcb8763 100644 --- a/Utils/XML_Items.cpp +++ b/Utils/XML_Items.cpp @@ -275,6 +275,7 @@ itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **at strcmp(name, "CrowbarModifier") == 0 || strcmp(name, "DisarmModifier") == 0 || strcmp(name, "RepairModifier") == 0 || + strcmp(name, "usHackingModifier" ) == 0 || strcmp(name, "usActionItemFlag") == 0 || strcmp(name, "clothestype") == 0 || @@ -1396,6 +1397,11 @@ itemEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->curItem.RepairModifier = (INT8) atol(pData->szCharData); } + else if ( strcmp( name, "usHackingModifier" ) == 0 ) + { + pData->curElement = ELEMENT; + pData->curItem.usHackingModifier = min(100, (UINT8)atol( pData->szCharData ) ); + } else if(strcmp(name, "DamageChance") == 0) { pData->curElement = ELEMENT; @@ -2106,6 +2112,7 @@ BOOLEAN WriteItemStats() FilePrintf(hFile, "\t\t%d\r\n", Item[cnt].CrowbarModifier ); FilePrintf(hFile, "\t\t%d\r\n", Item[cnt].DisarmModifier ); FilePrintf(hFile, "\t\t%d\r\n", Item[cnt].RepairModifier ); + FilePrintf(hFile, "\t\t%d\r\n", Item[cnt].usHackingModifier ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].usDamageChance ); FilePrintf(hFile,"\t\t%4.2f\r\n", Item[cnt].dirtIncreaseFactor ); diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 1d609a34..51302bef 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -8832,7 +8832,7 @@ STR16 szPrisonerTextStr[]= L"敌人不肯拿你当囚犯 - 他们宁愿你死!", //L"The enemy refuses to take you as prisoners - they prefer you dead!", L"这些可以在 INI 设置关闭。", // L"This behaviour is set OFF in your ini settings.", L"%s释放了%s!", //L"%s has freed %s!", - L"囚犯会暴露高级军官的位置 %s!", //L"A prisoner revealed the location of a high-ranking army officer in %s!", + L"A high-ranking army officer in %s has been revealed!", // TODO.Translate L"敌方首领会拒绝即使被认为投降!", //L"The enemy leader refuses to even consider surrender!", L"%d 囚犯自愿加入我军。", //L"%d prisoners volunteered to join our forces.", }; @@ -8842,6 +8842,7 @@ STR16 szMTATextStr[]= L"空无一物", L"建造掩体", //L"building a fortification", L"拆除掩体", //L"removing a fortification", + L"hacking", // TODO.Translate L"%s必须停止%s", //L"%s had to stop %s.", L"所选的路障无法再该分区建造", }; @@ -8953,6 +8954,7 @@ STR16 szBackgroundText_Value[]= L"非吸烟者", //L"Nonsmoker", L" %s%d%% 如果敌人 CTH 蹲在厚覆盖他们的方向\n", //L" %s%d%% enemy CTH if crouched against thick cover in their direction\n", L" %s%d%% building speed\n", + L" hacking skill: %s%d ", // TODO.Translate }; STR16 szBackgroundTitleText[] = @@ -11160,6 +11162,21 @@ STR16 szSMilitiaResourceText[] = L"Not enough resources to train militia!", }; +STR16 szInteractiveActionText[] = +{ + L"%s starts hacking.", + L"%s accesses the computer, but finds nothing of interest.", + L"%s is not skilled enough to hack the computer.", + L"%s reads the file, but learns nothing new.", + + L"%s can't make sense out of this.", + L"%s couldn't use the watertap.", + L"%s has bought a %s.", + L"%s doesn't have enough money. That's just embarassing.", + + L"%s drank from water tap", +}; + // WANNE: Some Chinese specific strings that needs to be in unicode! STR16 ChineseSpecString1 = L"%%"; //defined in _ChineseText.cpp as this file is already unicode STR16 ChineseSpecString2 = L"*%3d%%%%"; //defined in _ChineseText.cpp as this file is already unicode diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index cfd16d72..e0a5b7e8 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -8847,7 +8847,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", - L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate + L"A high-ranking army officer in %s has been revealed!", // TODO.Translate L"The enemy leader refuses to even consider surrender!", L"%d prisoners volunteered to join our forces.", }; @@ -8857,6 +8857,7 @@ STR16 szMTATextStr[]= // TODO.Translate L"nothing", L"building a fortification", L"removing a fortification", + L"hacking", // TODO.Translate L"%s had to stop %s.", L"The selected barricade cannot be built in this sector", // TODO.Translate }; @@ -8970,6 +8971,7 @@ STR16 szBackgroundText_Value[]= L"Nonsmoker", L" %s%d%% enemy CTH if crouched against thick cover in their direction\n", L" %s%d%% building speed\n", + L" hacking skill: %s%d ", // TODO.Translate }; STR16 szBackgroundTitleText[] = // TODO.Translate @@ -11177,4 +11179,19 @@ STR16 szSMilitiaResourceText[] = L"Not enough resources to train militia!", }; +STR16 szInteractiveActionText[] = +{ + L"%s starts hacking.", + L"%s accesses the computer, but finds nothing of interest.", + L"%s is not skilled enough to hack the computer.", + L"%s reads the file, but learns nothing new.", + + L"%s can't make sense out of this.", + L"%s couldn't use the watertap.", + L"%s has bought a %s.", + L"%s doesn't have enough money. That's just embarassing.", + + L"%s drank from water tap", +}; + #endif //DUTCH diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index 8abf2cc2..63325846 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -8830,7 +8830,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", - L"A prisoner revealed the location of a high-ranking army officer in %s!", + L"A high-ranking army officer in %s has been revealed!", L"The enemy leader refuses to even consider surrender!", L"%d prisoners volunteered to join our forces.", }; @@ -8840,6 +8840,7 @@ STR16 szMTATextStr[]= L"nothing", L"building a fortification", L"removing a fortification", + L"hacking", L"%s had to stop %s.", L"The selected barricade cannot be built in this sector", }; @@ -8947,10 +8948,11 @@ STR16 szBackgroundText_Value[]= L" %s%d%% chance to evade snake attacks\n", L" dislikes some other backgrounds\n", - L"Smoker", - L"Nonsmoker", + L" Smoker", + L" Nonsmoker", L" %s%d%% enemy CTH if crouched against thick cover in their direction\n", L" %s%d%% building speed\n", + L" hacking skill: %s%d ", }; STR16 szBackgroundTitleText[] = @@ -11160,4 +11162,19 @@ STR16 szSMilitiaResourceText[] = L"Not enough resources to train militia!", }; +STR16 szInteractiveActionText[] = +{ + L"%s starts hacking.", + L"%s accesses the computer, but finds nothing of interest.", + L"%s is not skilled enough to hack the computer.", + L"%s reads the file, but learns nothing new.", + + L"%s can't make sense out of this.", + L"%s couldn't use the watertap.", + L"%s has bought a %s.", + L"%s doesn't have enough money. That's just embarassing.", + + L"%s drank from water tap", +}; + #endif //ENGLISH diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 29d9903a..02b171ee 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -8829,7 +8829,7 @@ STR16 szPrisonerTextStr[]= L"L'ennemi refuse votre reddition... Ils veulent vos têtes !", L"Ce comportement est désactivé dans vos fichiers ini.", L"%s a libéré %s !", - L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate + L"A high-ranking army officer in %s has been revealed!", // TODO.Translate L"The enemy leader refuses to even consider surrender!", L"%d prisoners volunteered to join our forces.", }; @@ -8839,6 +8839,7 @@ STR16 szMTATextStr[]= L"rien, en fait.", L"la construction d'une fortification", L"le retrait d'une fortification", + L"hacking", // TODO.Translate L"%s a dû arrêter... %s", L"Cette sorte de barricade ne peut pas être construite dans ce secteur", }; @@ -8952,6 +8953,7 @@ STR16 szBackgroundText_Value[]= L"Nonsmoker", L" %s%d%% enemy CTH if crouched against thick cover in their direction\n", L" %s%d%% building speed\n", + L" hacking skill: %s%d ", // TODO.Translate }; STR16 szBackgroundTitleText[] = @@ -11159,4 +11161,19 @@ STR16 szSMilitiaResourceText[] = L"Not enough resources to train militia!", }; +STR16 szInteractiveActionText[] = +{ + L"%s starts hacking.", + L"%s accesses the computer, but finds nothing of interest.", + L"%s is not skilled enough to hack the computer.", + L"%s reads the file, but learns nothing new.", + + L"%s can't make sense out of this.", + L"%s couldn't use the watertap.", + L"%s has bought a %s.", + L"%s doesn't have enough money. That's just embarassing.", + + L"%s drank from water tap", +}; + #endif //FRENCH diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index bc064779..5463fba4 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -8659,7 +8659,7 @@ STR16 szPrisonerTextStr[]= L"Der Feind weigert sich, Sie als Gefangenen zu nehmen - Er möchte Sie tod sehen!", L"Dieses Verhalten ist ausgeschaltet in der ja2_options.ini Datei.", L"%s hat %s befreit!", - L"Ein Gefangener hat den Aufenthaltsort eines hochrangigen Offiziers in %s enthüllt!", + L"A high-ranking army officer in %s has been revealed!", // TODO.Translate L"Der feindliche Anführer denkt nicht mal an Kapitulation!", L"%d Gefangene sind uns als Freiwillige beigetreten.", }; @@ -8669,6 +8669,7 @@ STR16 szMTATextStr[]= L"nichts", L"baue eine Befestigung", L"entferne eine Befestigung", + L"hacking", // TODO.Translate L"%s musste %s stoppen.", L"The selected barricade cannot be built in this sector", // TODO.Translate }; @@ -8782,6 +8783,7 @@ STR16 szBackgroundText_Value[]= L"Nonsmoker", L" %s%d%% enemy CTH if crouched against thick cover in their direction\n", L" %s%d%% building speed\n", + L" hacking skill: %s%d ", // TODO.Translate }; STR16 szBackgroundTitleText[] = // TODO.Translate @@ -10989,4 +10991,19 @@ STR16 szSMilitiaResourceText[] = L"Not enough resources to train militia!", }; +STR16 szInteractiveActionText[] = +{ + L"%s starts hacking.", + L"%s accesses the computer, but finds nothing of interest.", + L"%s is not skilled enough to hack the computer.", + L"%s reads the file, but learns nothing new.", + + L"%s can't make sense out of this.", + L"%s couldn't use the watertap.", + L"%s has bought a %s.", + L"%s doesn't have enough money. That's just embarassing.", + + L"%s drank from water tap", +}; + #endif //GERMAN diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 53f7c322..8d12424f 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -8837,7 +8837,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", - L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate + L"A high-ranking army officer in %s has been revealed!", // TODO.Translate L"The enemy leader refuses to even consider surrender!", L"%d prisoners volunteered to join our forces.", }; @@ -8847,6 +8847,7 @@ STR16 szMTATextStr[]= // TODO.Translate L"nothing", L"building a fortification", L"removing a fortification", + L"hacking", // TODO.Translate L"%s had to stop %s.", L"The selected barricade cannot be built in this sector", // TODO.Translate }; @@ -8961,6 +8962,7 @@ STR16 szBackgroundText_Value[]= L"Nonsmoker", L" %s%d%% enemy CTH if crouched against thick cover in their direction\n", L" %s%d%% building speed\n", + L" hacking skill: %s%d ", // TODO.Translate }; STR16 szBackgroundTitleText[] = // TODO.Translate @@ -11168,4 +11170,19 @@ STR16 szSMilitiaResourceText[] = L"Not enough resources to train militia!", }; +STR16 szInteractiveActionText[] = +{ + L"%s starts hacking.", + L"%s accesses the computer, but finds nothing of interest.", + L"%s is not skilled enough to hack the computer.", + L"%s reads the file, but learns nothing new.", + + L"%s can't make sense out of this.", + L"%s couldn't use the watertap.", + L"%s has bought a %s.", + L"%s doesn't have enough money. That's just embarassing.", + + L"%s drank from water tap", +}; + #endif //ITALIAN diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index efc1d971..1770a93d 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -8851,7 +8851,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", - L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate + L"A high-ranking army officer in %s has been revealed!", // TODO.Translate L"The enemy leader refuses to even consider surrender!", L"%d prisoners volunteered to join our forces.", }; @@ -8861,6 +8861,7 @@ STR16 szMTATextStr[]= // TODO.Translate L"nothing", L"building a fortification", L"removing a fortification", + L"hacking", // TODO.Translate L"%s had to stop %s.", L"The selected barricade cannot be built in this sector", // TODO.Translate }; @@ -8974,6 +8975,7 @@ STR16 szBackgroundText_Value[]= L"Nonsmoker", L" %s%d%% enemy CTH if crouched against thick cover in their direction\n", L" %s%d%% building speed\n", + L" hacking skill: %s%d ", // TODO.Translate }; STR16 szBackgroundTitleText[] = // TODO.Translate @@ -11181,4 +11183,19 @@ STR16 szSMilitiaResourceText[] = L"Not enough resources to train militia!", }; +STR16 szInteractiveActionText[] = +{ + L"%s starts hacking.", + L"%s accesses the computer, but finds nothing of interest.", + L"%s is not skilled enough to hack the computer.", + L"%s reads the file, but learns nothing new.", + + L"%s can't make sense out of this.", + L"%s couldn't use the watertap.", + L"%s has bought a %s.", + L"%s doesn't have enough money. That's just embarassing.", + + L"%s drank from water tap", +}; + #endif //POLISH diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 20c03326..fca9cf7c 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -8830,7 +8830,7 @@ STR16 szPrisonerTextStr[]= L"Противник отказывается взять вас в плен - они предпочли бы видеть вас мертвыми!", L"Этот режим отключен в настройках.", L"%s освободил %s!", - L"Заключенный указал расположение высокопоставленного офицера в %s!", + L"A high-ranking army officer in %s has been revealed!", // TODO.Translate L"Вражеский командир отказывается даже подумать о сдаче!", L"%d заключенных добровольно присоединились к нашим силам.", }; @@ -8840,6 +8840,7 @@ STR16 szMTATextStr[]= L"ничего", L"укрепление строится", L"укрепление убирается", + L"hacking", // TODO.Translate L"%s был вынужден прекратить %s.", L"Выбранное укрепление не может быть построено в этом секторе", }; @@ -8951,6 +8952,7 @@ STR16 szBackgroundText_Value[]= L"Не курит", L" %s%d%% enemy CTH if crouched against thick cover in their direction\n", L" %s%d%% building speed\n", + L" hacking skill: %s%d ", // TODO.Translate }; STR16 szBackgroundTitleText[] = @@ -11160,4 +11162,19 @@ STR16 szSMilitiaResourceText[] = L"Not enough resources to train militia!", }; +STR16 szInteractiveActionText[] = +{ + L"%s starts hacking.", + L"%s accesses the computer, but finds nothing of interest.", + L"%s is not skilled enough to hack the computer.", + L"%s reads the file, but learns nothing new.", + + L"%s can't make sense out of this.", + L"%s couldn't use the watertap.", + L"%s has bought a %s.", + L"%s doesn't have enough money. That's just embarassing.", + + L"%s drank from water tap", +}; + #endif //RUSSIAN